views:

124

answers:

7

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

+2  A: 

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.

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.
Georg Fritzsche
Yes that's just what I'd be supposed to do with string parsing. Or am I missing something?
Johnny
+1  A: 

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

Daniel Egeberg
+2  A: 

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.

Jonathan Leffler
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
+3  A: 

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);
    }
}
aaa
+1  A: 

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)); 
Remy Lebeau - TeamB
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
rwong
@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.
Remy Lebeau - TeamB
+11  A: 

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; });
Georg Fritzsche
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
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.
Georg Fritzsche
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
Georg Fritzsche
I'm having an error in the highlighted line in next code, mind if you'd take a look at it? http://pastebin.com/YzGMPzFz
Johnny
That would have to be `ConditionalInput<T>(...)` - the type `T` isn't anywhere in the parameters and deduction on return types doesn't work. For the next time note that this would have been a perfectly fine question on its own :)
Georg Fritzsche
+1  A: 

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.

egrunin
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
This is a C-style solution, not a C++ one. C++ would use functors or lambda's (if your compiler supports them).
Sjoerd
I agree that it's a C-style solution, but it works and it's easy to understand.
egrunin