Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old May 3, 2011, 03:55 PM   #1
danwilliams
macrumors member
 
Join Date: Sep 2008
stl question

The question is in the comment section of the code block below.

Code:
#include <list>
#include <functional>

struct Foo
{
	Foo():_bar(0){}
	explicit Foo(const int bar):_bar(bar){}
	int Bar() const {return _bar;}
	bool less_equal(const int value) {return _bar <= value;}
private:
	int _bar;
};

int main(int argc, char* argv[])
{
	std::list<int> myInts;
	std::list<Foo> myFoos;
	for (int i=0; i<5; ++i)
	{
		myInts.push_back(i);
		myFoos.push_back(Foo(i));
	}
	// Remove all values that are less than 4.
	myInts.remove_if(std::bind2nd(std::less_equal<int>(),3));
	myFoos.remove_if(std::bind2nd(std::mem_fun_ref(&Foo::less_equal),3));
	// mInts  = [1](4)
	// myFoos = [1]({_bar=4})

	// How do I do the same as the lines above using the Foo::Bar member
	// function? The following obviously does not complete succesfully.
	//myFoos.remove_if(std::bind2nd(std::bind2nd(std::less_equal<int>(),3)),
	//                                         std::mem_fun_ref(&Foo::Bar));
	// In other words, I want to iterate through the list of Foo instances
	// and call the Bar() member function and pass it to std::less_equal.
	return 0;
}
danwilliams is offline   0 Reply With Quote
Old May 3, 2011, 04:22 PM   #2
jiminaus
macrumors 65816
 
Join Date: Dec 2010
Location: Sydney
What you asking doesn't make sense.

What you're asking is to implement something like the following (ill)logic:
Code:
foreach (element in myFoos) {
  if (element < element.less_equal(3)) {
     remove element from myFoos;
  }
}
You'd either use std::mem_fun_ref with your less_equal member function, or you'd use std::less_equal and define operator <= in Foo. You couldn't use both.
jiminaus is offline   0 Reply With Quote
Old May 3, 2011, 04:49 PM   #3
danwilliams
Thread Starter
macrumors member
 
Join Date: Sep 2008
Wow! That was a quick response. Thanks jiminaus.

Hmmm. I hate being illogical. Let me ask rephrase the question. I would like to do the following:
Code:
for (std::list<Foo>::iterator it=myFoos.begin(); it!=myFoos.end(); ++it)
{
    if (it->Bar() <= 3)
    {
        myFoos.remove(*it);
    }
}
But I wanted to do all within the std::list::remove_if() function.

And the reason I don't use the Foo::less_than() function is that I don't own the Foo class and it doesn't have that implemented in my real code base. (I just added it here as an example) I can't modify Foo. All that Foo provides is the Foo::Bar() function.

Last edited by kainjow; May 3, 2011 at 09:23 PM. Reason: merged posts
danwilliams is offline   0 Reply With Quote
Old May 3, 2011, 06:31 PM   #4
jiminaus
macrumors 65816
 
Join Date: Dec 2010
Location: Sydney
Quote:
Originally Posted by danwilliams View Post
Wow! That was a quick response. Thanks jiminaus.

Hmmm. I hate being illogical. Let me ask rephrase the question. I would like to do the following:
Code:
for (std::list<Foo>::iterator it=myFoos.begin(); it!=myFoos.end(); ++it)
{
    if (it->Bar() <= 3)
    {
        myFoos.remove(*it);
    }
}
But I wanted to do all within the std::list::remove_if() function.
Quote:
Originally Posted by danwilliams View Post
And the reason I don't use the Foo::less_than() function is that I don't own the Foo class and it doesn't have that implemented in my real code base. (I just added it here as an example) I can't modify Foo. All that Foo provides is the Foo::Bar() function.
Sorry Dan. I misread your initial comment. I though you wanted to call less_equal not Bar.

I don't know how to do this with bindings. My C++ knowledge is rusty. My C++ template meta-programming knowledge is poor.

Here's a solution I came up with:
Code:
struct foo_bar_less_equal : std::binary_function<Foo, int, bool> {
  bool operator ()(Foo a, int b) const {
    return a.Bar() <= b;
  }
};

// And then later

myFoos.remove_if(std::bind2nd(foo_bar_less_equal(), 3));
I think C++0x add stuff so you don't need the explicit class, but I don't know it.
jiminaus is offline   0 Reply With Quote
Old May 3, 2011, 06:56 PM   #5
danwilliams
Thread Starter
macrumors member
 
Join Date: Sep 2008
Quote:
Originally Posted by jiminaus View Post
Sorry Dan. I misread your initial comment. I though you wanted to call less_equal not Bar.

I don't know how to do this with bindings. My C++ knowledge is rusty. My C++ template meta-programming knowledge is poor.

Here's a solution I came up with:
Code:
struct foo_bar_less_equal : std::binary_function<Foo, int, bool> {
  bool operator ()(Foo a, int b) const {
    return a.Bar() <= b;
  }
};

// And then later

myFoos.remove_if(std::bind2nd(foo_bar_less_equal(), 3));
I think C++0x add stuff so you don't need the explicit class, but I don't know it.
Ha! My C++ template meta-programming knowledge is poor as well. That's why I am here. ;-)

Yep. I came up with that functor too. It's fine when you just have one function method you are using in std::remove_if. But in my case there are several and coming up with a functor for each one is a maintenance headache. For example:
Code:
struct foo_bar1_less_equal ...;
struct foo_bar2_less_equal ...;
struct foo_bar3_less_equal ...;
// etc...
I was hoping to use bindings to eliminate the need to write a function object like you posted. Hmmm. Maybe I should look into boost::bind?

Last edited by danwilliams; May 4, 2011 at 11:04 AM. Reason: grammar
danwilliams is offline   0 Reply With Quote
Old May 3, 2011, 07:01 PM   #6
jiminaus
macrumors 65816
 
Join Date: Dec 2010
Location: Sydney
Quote:
Originally Posted by danwilliams View Post
Ha! My C++ template meta-programming knowledge is poor as well. That's why I am here. ;-)

Yep. I came up with that functor too. It's fine when you just have one function method you are using in std::remove_if. But in my case there are several and coming up with a functor for each one is maintenance headache. For example:
Code:
struct foo_bar1_less_equal ...;
struct foo_bar2_less_equal ...;
struct foo_bar3_less_equal ...;
// etc...
I was hoping to use bindings to eliminate the need to write a function object like you posted. Hmmm. Maybe I should look into boost::bind?
I'd forgotten about boost. Yes try that. Boost has excellent template meta-programming tools.

Hopefully someone else here with Boost experience and at least a current working knowledge of C++ can help you better.


EDIT: Wow!! Boost is awesome!!

Code:
#include <list>
#include <functional>
#include <iostream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

struct Foo
{
	Foo():_bar(0){}
	explicit Foo(const int bar):_bar(bar){}
	int Bar() const {return _bar;}
	bool less_equal(const int value) {return _bar <= value;}
private:
	int _bar;
};

int main(int argc, char* argv[])
{
    using namespace boost::lambda;
    
    std::list<int> myInts;
    std::list<Foo> myFoos;
    for (int i=0; i<5; ++i)
    {
        myInts.push_back(i);
	myFoos.push_back(Foo(i));
    }

//  myInts.remove_if(std::bind2nd(std::less_equal<int>(), 3));
    myInts.remove_if(_1 <= 3);
	
//	myFoos.remove_if(std::bind2nd(std::mem_fun_ref(&Foo::less_equal),3));
    myFoos.remove_if(bind(&Foo::Bar, _1) <= 3);
	
    return 0;
}
Who needs Apple's blocks when you've got Boost's lambdas?!

Last edited by jiminaus; May 4, 2011 at 04:35 AM. Reason: Figured out how to do it Boost.
jiminaus is offline   0 Reply With Quote
Old May 4, 2011, 05:31 AM   #7
ShortCutMan
macrumors member
 
Join Date: Aug 2005
Here is one way to do it:
Code:
#include <list>
#include <boost/bind.hpp>

struct Foo
{
	Foo():_bar(0){}
	explicit Foo(const int bar):_bar(bar){}
	int Bar() const {return _bar;}
	
	static bool less_equal(const Foo& obj, int value) {return obj.Bar() <= value;};
private:
	int _bar;
};

int main(int argc, char* argv[])
{
	std::list<int> myInts;
	std::list<Foo> myFoos;
	for (int i=0; i<5; ++i)
	{
		myInts.push_back(i);
		myFoos.push_back(Foo(i));
	}
	// Remove all values that are less than 4.
	myInts.remove_if(std::bind2nd(std::less_equal<int>(),3));
	myFoos.remove_if(std::bind2nd(std::mem_fun_ref(&Foo::less_equal),3));
	// mInts  = [1](4)
	// myFoos = [1]({_bar=4})

	myFoos.remove_if(boost::bind(&Foo::less_equal, _1, 3));
	
	return 0;
}
There I bind the address of the function, notate (using '_1') that there is one parameter that will be passed in by the caller of the bind object, and pass in the value 3 to the second parameter. Note I also made the function static and added the parameter required by the remove_if predicate as noted in STL docs (http://www.cplusplus.com/reference/stl/list/remove_if/, I use this website at work). I haven't compiled this code, as I don't have a build of boost setup here at home, but I use it all the time at work. This problem would be a solvable using lambdas in C++0x. Boost lambdas are ugly and I personally wouldn't use nor encourage them.
__________________
27" iMac 2.66GHz, 15" MBP (Late '07) 2.4GHz, iPhone 3GS 32GB
ShortCutMan is offline   0 Reply With Quote
Old May 4, 2011, 05:36 AM   #8
jiminaus
macrumors 65816
 
Join Date: Dec 2010
Location: Sydney
ShortCutMan, is there a way to use boost's bind (not boost's lambda bind) without calling Foo's less_equal? That is can the call to Bar() be build into the bind expression?

The OP said subsequently that less_equal doesn't actually exist in the class he's actually trying to use, and he can't change the class. And there's apparently more than just Bar() he needs to use in these kinds of expressions.
jiminaus is offline   0 Reply With Quote
Old May 4, 2011, 07:42 AM   #9
danwilliams
Thread Starter
macrumors member
 
Join Date: Sep 2008
Quote:
Originally Posted by jiminaus View Post
ShortCutMan, is there a way to use boost's bind (not boost's lambda bind) without calling Foo's less_equal? That is can the call to Bar() be build into the bind expression?

The OP said subsequently that less_equal doesn't actually exist in the class he's actually trying to use, and he can't change the class. And there's apparently more than just Bar() he needs to use in these kinds of expressions.
jiminaus, do you ever sleep? And yes, (unfortunately) I can't add to the Foo class by adding Foo::less_equal().


Quote:
myFoos.remove_if(boost::bind(&Foo::Bar, _1) <= 3);
Winner! Yes, that is exactly what I was hoping for (and I agree that boost is awesome). I also can't wait to upgrade our compilers to C++ 0x to take advantage of lambdas. As of now, I will look to boost.

I will now spend some quality time with stl, boost, and my compiler. Thanks to everyone.

Last edited by danwilliams; May 4, 2011 at 07:50 AM. Reason: grammar
danwilliams is offline   0 Reply With Quote
Old May 4, 2011, 09:27 AM   #10
danwilliams
Thread Starter
macrumors member
 
Join Date: Sep 2008
Here is what I ended up with:
Code:
#include <list>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

struct Foo
{
    Foo():_bar(0){}
    explicit Foo(const int bar):_bar(bar){}
    int Bar() const {return _bar;}
private:
    int _bar;
};

int main(int argc, char* argv[])
{
    std::list<Foo> myFoos;
    for (int i=0; i<5; ++i)
    {
        myFoos.push_back(Foo(i));
    }
    // myFoos = [5]({_bar=0},{_bar=1},{_bar=2},{_bar=3},{_bar=4})

    // Remove all values that are less than 4.
    myFoos.remove_if(boost::lambda::bind(&Foo::Bar, boost::lambda::_1) <= 3);
    // myFoos = [1]({_bar=4})
    return 0;
}
Quote:
Originally Posted by ShortCutMan View Post
There I bind the address of the function, notate (using '_1') that there is one parameter that will be passed in by the caller of the bind object, and pass in the value 3 to the second parameter. Note I also made the function static and added the parameter required by the remove_if predicate as noted in STL docs (http://www.cplusplus.com/reference/stl/list/remove_if/, I use this website at work). I haven't compiled this code, as I don't have a build of boost setup here at home, but I use it all the time at work. This problem would be a solvable using lambdas in C++0x. Boost lambdas are ugly and I personally wouldn't use nor encourage them.
The boost lambdas may be ugly but I would submit so is writing extra one off functors/functions. I hear what you are saying though. Unfortunately, we can't upgrade yet to C++0x to take advantage of the new built in lambda support.

This allows me to write less code. Now I must make sure I write concise comments explaining what is happening at the point of the std::list::remove_if() call.

Last edited by danwilliams; May 4, 2011 at 11:05 AM. Reason: clarification
danwilliams is offline   0 Reply With Quote
Old May 4, 2011, 05:35 PM   #11
ShortCutMan
macrumors member
 
Join Date: Aug 2005
I see what you mean also, I'm probably just used to seeing boost bind more so than boost lambda. Sometimes I have seen people write nested structs in the calling function if it is once off, or just put it in an anonymous namespace since it doesn't really need to be a class member function.

Either way, you've found a solution that works for you.
__________________
27" iMac 2.66GHz, 15" MBP (Late '07) 2.4GHz, iPhone 3GS 32GB
ShortCutMan is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Mophie Juice Pack Plus (iPhone 5) Question - Mute Button Question JulesK iPhone Accessories 3 Mar 30, 2014 02:58 PM
Snow Leopard File Vault Question and Basic System Password Question & Time Machine? GordonGekko999 Mac Basics and Help 0 Oct 25, 2013 06:06 AM
Question for anyone who has seen or owns the pink ipod nano? Color deciding question. Pinkstiletto66 iPod 4 Apr 4, 2013 12:57 PM
Family Share Question, Upgrade Question, Argh head hurting.. Jazwire iPhone 1 Sep 14, 2012 12:19 AM
Time Capsule - Newbie Question Wifi Question Alper1234 Mac Peripherals 1 Jun 23, 2012 09:17 AM

Forum Jump

All times are GMT -5. The time now is 09:22 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC