2

i'm in this situation:

template<class  T>
void testFuncMulti (set<T> setInput,  bool (*f)() ) { 
  f();
}

 bool func()
{
    cout   << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testSet; 
        testSet.insert("XXX");
     testFuncMulti(testSet,  &func); 
    return 0;
} 

What I would like to achieve is passing a parameter to the last function "func".

Tried in many many different ways but still nothing.

This is my attempt:

template<class  T>
void testFuncMulti (set<T> setInput,  bool (*f)(T) ) { 
  f(T);
}

template<class  T>
 bool func(T val)
{
    cout   << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testSet; 
        testSet.insert("XXX");
     testFuncMulti(testSet,  &func(string("YYY"))); 
    return 0;
} 

Sorry i'm a c++ newbie...pls help!

UPDATE:

SOLVED!!

#include <iostream>
#include <functional>
#include <set>
 using namespace std;

template<class  T, class U>
void testFuncMulti (const set<T> setInput, U f) { 

     typename set<T>::iterator iter;
                for(iter = setInput.begin();iter != setInput.end();++iter) {
                        f(*iter); 
                }
}

template<class  T>
 bool func(const T val)
{   

    cout <<val  << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testInput; 
        testInput.insert("XXX");
         testInput.insert("XXX222");
    testFuncMulti(testSet,   func<string> );  
    return 0;
}
Black.Jack
  • 1,755
  • 2
  • 19
  • 35

2 Answers2

2

The thing you are trying to achieve is called function binding. Also, the parameter should be written in C++ way - std::function<bool()>. Or, as @chris mentioned in comments, use another parameter with anything callable.

It can be achieved in two ways here. The STL one:

template<class  T, class U>
void testFuncMulti (set<T> setInput, U f) { 
  f();
}

template<class  T>
 bool func(T val)
{
    cout   << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testSet; 
        testSet.insert("XXX");
     testFuncMulti(testSet,  std::bind(func<int>, string("YYY"))); 
    return 0;
} 

or using lambda:

template<class  T, class U>
void testFuncMulti (set<T> setInput, U f) { 
  f();
}

template<class  T>
 bool func(T val)
{
    cout   << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testSet; 
        testSet.insert("XXX");
     testFuncMulti(testSet, []() { return func("YYY"); }); 
    return 0;
} 

However, it is probably not very useful for you - I assume you want to pass something to the function as well.

In that case, the binding can be partial. Also, you probably want to pass the object by reference.

template<class  T, class U>
void testFuncMulti (const set<T>& setInput, U f) { 
  f(*setInput.begin());
}

template<class  T>
 bool func(const T& val, const T& second)
{
    cout   << "Hello!" <<  endl;  
    return true;
}

int main() { 
    set<string> testSet; 
        testSet.insert("XXX");
     testFuncMulti(testSet,  std::bind(func<int>, string("YYY"))); 
    return 0;
}
nothrow
  • 14,840
  • 6
  • 50
  • 97
  • 1
    you second example forget to return something. – apple apple Mar 16 '17 at 12:23
  • `std::function` is overkill for this. `testFuncMulti` is already a template, just make the template parameter any callable object instead of type-erasing it into a `std::function`. Lambdas are almost always better to use than `std::bind` as well, and this comes from the people actually writing the implementation of `std::bind`. – chris Mar 16 '17 at 12:28
  • @chris, I agree (and I've updated the question), however, for newbie in C++ I find approach with `std::function` little bit easier to explain. – nothrow Mar 16 '17 at 12:31
  • @chris Would you have a link/reference to implementors of a standard library implementation's `std::bind` preferring lambdas? I'd like to read more: I actually prefer using `std::bind` where its use is straightforward, and I'd be very interested in other perspectives. – Angew is no longer proud of SO Mar 16 '17 at 12:34
  • @Angew, it is elaborated in http://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14. I personally prefer `std::bind` over lambda, as it makes the intent more clear - with `std::bind`, you are explicitely stating that you are doing bind, whereas with lambda you can easily end up with also creating closure (and trigger allocation even when not necessary) – nothrow Mar 16 '17 at 12:37
  • sorry tried your code to https://www.codechef.com/ide but seems bind function not available in std... thanks for coop! – Black.Jack Mar 16 '17 at 12:38
  • 1
    @Mark, `#include `. – nothrow Mar 16 '17 at 12:38
  • Ok included but: prog.cpp: In function 'int main()': prog.cpp:22:60: error: 'bind' was not declared in this scope testFuncMulti(testSet, bind(func, string("YYY"))); I'm running your last attempt. – Black.Jack Mar 16 '17 at 12:41
  • @Mark You seem to have forgotten the `std::` qualification there. – Angew is no longer proud of SO Mar 16 '17 at 12:42
  • Your are right but I've put #include and: using namespace std; but still same error... :(( – Black.Jack Mar 16 '17 at 12:43
  • @Mark Any chance you could link to the code you're actually trying? On e.g. [coliru](http://coliru.stacked-crooked.com/) you can create permalinks. – Angew is no longer proud of SO Mar 16 '17 at 12:45
  • @chris Thanks, I'll definitely take a look. – Angew is no longer proud of SO Mar 16 '17 at 12:45
  • @Mark I can see errors about `` not being included (and further errors caused by that), but not a single complaint about missing `bind`. – Angew is no longer proud of SO Mar 16 '17 at 12:54
  • http://coliru.stacked-crooked.com/a/4a1bbed89e8835d3 or http://coliru.stacked-crooked.com/a/5f83f7a1ca15c345 nothing works. Don't get why. – Black.Jack Mar 16 '17 at 12:58
  • Oh it was here: testFuncMulti(testSet, bind(func, string("YYY"))); – Black.Jack Mar 16 '17 at 13:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/138227/discussion-between-mark-and-angew). – Black.Jack Mar 16 '17 at 13:25
  • @Angew, The idea of `bind` is definitely nice. Apart from the initial learning curve of the mini placeholders EDSL, it looks pretty clean. At that point, the main thing would be ease of optimization. On the plus side, [this proposal](https://wg21.link/p0573r0) is looking well-received by the community so far. It would allow lambdas to match `bind` in conciseness: `[](x) => x < 5` – chris Mar 16 '17 at 14:05
  • @chris Very interesting proposal. However, I like `bind` not only for conciseness, but also for its clear statement of intent. With `bind`, it's obvious you're just binding a function (as in lambda calculus). With a lambda (even a terse one), you have to inspect it to understand it does a bind and not e.g. composition. – Angew is no longer proud of SO Mar 16 '17 at 14:15
2

When you pass a function pointer as parameter, it is not the same instant than when you call the function pointer:

For this reason, the parameter need to be saved somewhere and retrieved by the call. Either by a reference (so the value may be changed in between), or by value (so the moment of registering the function define the value of the parameters).

In both cases, it seem the lambdas/functors to be the most appropriate solution:

#include <iostream>
#include <functional>
#include <set>

template<class  T>
void testFuncMulti (std::set<T> setInput,  std::function<bool()> f ) { 
  f();
}

int main() { 
    std::set<std::string> testSet; 
        testSet.insert("XXX");
    int value = 42; // I like this number
    auto func = [&value]()->bool
    {
        std::cout << "Hello world! " << value << std::endl;
        return true;
    };
    testFuncMulti(testSet,  func); 
    return 0;
} 

.

EDITED: Based on OP comment, the solution without lambdas or functional (should be compatible C++98):

#include <iostream>
#include <set>

template<class  T, class U>
void testFuncMulti (std::set<T> setInput,  U f ) {
  f();
}

struct Functor
{
    int value;
    bool operator()()
    {
        std::cout << "Hello world! " << value << std::endl;
        return true;
    }
};

int main() {
    std::set<std::string> testSet;
        testSet.insert("XXX");

    Functor func;
    func.value = 42; // I like this number
    testFuncMulti(testSet,  func);
    return 0;
}
Adrian Maire
  • 11,506
  • 8
  • 34
  • 72