6

First of all to explain what I'm trying to do:

void Foo(int &num, bool condition);

Foo(x, x > 3);

This code basically would evaluate the bool of the condition before calling the function and then pass pure true or false. I'm looking for a way to make it pass the condition itself, so I could do something like this:

void Foo(int &num, bool condition)
{
    while(!condition)
    {
        num = std::rand();
    }
}

I know there could be a workaround by passing a string containing the condition and parsing the latter, and I'm working on it right now, but I find it rather inefficient way. The accepted answer will be the one explaining the solution on any other way beside the one with parsing the string containing the condition, or an answer that clarifies that this way of passing conditions is impossible.

Thanks in advance

4
  • 1
    Is there a bigger picture so we can see Foo (pretend it works as you want) in a real situation? Also, you pass x as the parameter when it's a reference, not the address of x.
    – GManNickG
    Commented Jul 24, 2010 at 6:06
  • 1
    If thats std::rand() note that it returns an int and takes no arguments. Commented Jul 24, 2010 at 6:10
  • Yeah I didn't check it, I just wrote it to give an idea how things should work. I'm really sorry that the code is laughable but I wrote it under few minutes directly here. @GMan - well I can copy and paste the code, but it might happen to miss some parts, so I just wanted to give the idea. What it's supposed to do is to ask user for input again and again as long as the condition isn't put in respect.
    – Johnny
    Commented Jul 24, 2010 at 6:30
  • There's not going to be each Foo call. Instead the function is supposed to run a while loop checking the condition, and asking for the input over and over again just as I said in the comment above.
    – Johnny
    Commented Jul 24, 2010 at 6:50

7 Answers 7

13

One example using a standard library functor:

#include <functional>

template<class UnaryPred> void func(int& num, UnaryPred predicate) {
    while(!predicate(num)) num = std::rand();
}

void test() {
    int i = 0;
    func(i, std::bind1st(std::greater<int>(), 3));
}

See the documentation on <functional> for what C++ already provides you with out-of-the-box.

If your compiler has sufficient support (e.g. GCC 4.5 or VC10), you can also go for lambda functions. E.g. using the same func() as above:

func(i, [](int num) { return num > 3; });
6
  • This is most likely exactly what I need, and most likely an accepted answer, just I wanna check it and see how it works out. About the lambda function (I'm using VC10), how do I invoke it in the function?
    – Johnny
    Commented Jul 24, 2010 at 6:46
  • Exactly like in func() in the first example: predicate(someNumber). The lambda expression also generates a functor in the background, its just that the compiler does it for you and you get much nicer syntax. Commented Jul 24, 2010 at 6:53
  • Oh, sorry I thought that the latter code is independent from the code above. So it's only simplified call of the func? Thanks!
    – Johnny
    Commented Jul 24, 2010 at 6:56
  • Yep, basically the second example is just an easier version of the first. See e.g. here for some more information about lambdas. Commented Jul 24, 2010 at 7:06
  • I'm having an error in the highlighted line in next code, mind if you'd take a look at it? pastebin.com/YzGMPzFz
    – Johnny
    Commented Jul 24, 2010 at 8:56
3

this is called functional programming.

here is snippet using boost::phoenix http://www.boost.org/doc/libs/1_43_0/libs/spirit/phoenix/doc/html/phoenix/starter_kit.html:

using namespace boost::phoenix;

Foo(x, (cref(x) < 3));
// (cref(x) < 3) is expression that creates function object

template<class C> // condition is a monster, make it generic
void Foo(int &num, C condition)
{
    while(!condition()) // notice you call condition as function
    {
        rand(num);
    }
}
2

What you should do is create a function which tests your condition, then pass a pointer to that function as a parameter. See http://www.cprogramming.com/tutorial/function-pointers.html for details/tutorials on how to do this.

2
  • But with function pointers you'd need to either pass the bound as well or create a function for every bound needed - plain functions don't carry any state. Commented Jul 24, 2010 at 6:25
  • Yes that's just what I'd be supposed to do with string parsing. Or am I missing something?
    – Johnny
    Commented Jul 24, 2010 at 6:31
2

The plausible way to do this would pass a functor - and object that behaves like a function - to the called function, and the called function would invoke the functor to re-evaluate the condition on each iteration of the loop.

Parsing the string is not going to work; the called function does not have access to the local variables of the calling function.

1
  • The string approach is based on the fact that this is used for user's numerical input, so there would be only one variable to check, that could be passed as reference, and assigned to the result if the input is in the respect of the condition. Otherwise functors are what I need, thanks, vote up.
    – Johnny
    Commented Jul 24, 2010 at 6:42
1

Pass a function to Foo instead. Then you can "delay" the execution of the expression by waiting to call that function.

1

You can do this without templates or boost (a commenter called this "C-style", which is correct I suppose).

/* have Foo take a pointer to a function that returns bool */
void Foo(int &num, bool (*fcn)(int))
{
    while(!fcn(num))
    {
        num = std::rand();
    }
}

/* You can have all the Comparators you want, 
   as long as they have the same signature */
bool ComparatorOne(int x) { return x > 3 ? true : false; }

bool ComparatorTwo(int x) { return x < 10 ? true : false; }

/* and this is how you call it */
int n;
Foo(n, ComparatorOne);
Foo(n, ComparatorTwo);

Edit

Note that your Comparator can take a different set of parameters, as long as they're consistent.

3
  • I'm sorry that my question is unclear, but I need it for any sort of condition, not only for integers also. It's gotta be universal. Anyways, thanks for the tip and example of such solution, vote up!
    – Johnny
    Commented Jul 24, 2010 at 7:17
  • This is a C-style solution, not a C++ one. C++ would use functors or lambda's (if your compiler supports them).
    – Sjoerd
    Commented Jul 24, 2010 at 7:23
  • I agree that it's a C-style solution, but it works and it's easy to understand.
    – egrunin
    Commented Jul 24, 2010 at 7:25
1

As others have said, pass a functor object into Foo(). The STL commonly uses this approach. For example:

template< class Func >
void Foo(int &num, Func condition) 
{ 
    while(!condition()) 
    { 
        rand(num); 
    } 
} 

struct GreaterThanThree
{
    int& _num;
    GreaterThanThree(int &num) : _num(num) {}
    bool operator()() const { return (_num > 3); }
};

Foo(x, GreaterThanThree(x)); 
3
  • Well I'm not only using greater than three situation only, since this is meant to be a library containing commonly used conditional input. Otherwise, I'm still pretty unexperienced with C++'s advanced possibilities, so I've gotta ask what does the struct GreaterThanThree represent (it's not an usual struct). Possibly you could give a link to reference about such structs or something similar?
    – Johnny
    Commented Jul 24, 2010 at 6:36
  • @Johnny: It is a functor. @Remy: In order to allow the functor to have mutable state, Foo should take Func& condition by reference.
    – rwong
    Commented Jul 24, 2010 at 7:02
  • @rwong: sure, if you need to pass in the same functor object multiple times. That is not common, though. I have only ever seen functors used with temporary instances, similar to how I showed. Commented Jul 27, 2010 at 3:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.