Lambda as template parameter

c++, c++11, lambda, templates

Solution

As the compiler is helpfully telling you, the problem is with this line:

return Order(val, other.val);

Since `Order` is a type (and not a function), that is calling Order's two-argument constructor. But it doesn't have one.

The correct syntax for invoking a functional class is:

return Order()(val, other.val);

However, that won't work either because the class generated for the lambda has a deleted default constructor.

In short, you need to instantiate your class with (the only) instance of the lambda.

Here's one possible way to proceed:

template<typename Order>
struct foo {
    foo(Order compare) : compare_(compare) {}
    bool operator<(const foo& other) {
        return compare_(val, other.val);
    }
    int val;
    Order compare_;
};

/* In practice, you'll want to template a parameter pack
 * for the other arguments to the constructor, since those are likely.
 * Also, you might want to use std::forward.
 */
template<typename Order>
foo<Order> foomaker(Order order) {
    return foo<Order>(order);
}

int main() {
    auto GoLess = [](int a,int b) -> bool
        {
             return a < b;
        };

    auto a = foomaker(GoLess);
    auto b = foomaker(GoLess);
    bool r = a < b;
    return r;
}

Problem

I found those similar questions Lambda expressions as class template parameters and How to use a lambda expression as a template parameter?, but even with the answers available I didnt get why the following code isn't working (g++4.8.2 and g++-4.9): ``` auto GoLess = [](int a,int b) -> bool { return a < b; }; template<typename Order> struct foo { int val; bool operator<(const foo& other) { return Order(val, other.val); } }; typedef foo<decltype(GoLess)> foo_t; int main() { foo_t a,b; bool r = a < b; } ``` The compiler output is: ``` test.cpp: In instantiation of ‘bool foo<Order>::operator<(const foo<Order>&) [with Order = <lambda(int, int)>]’: test.cpp:26:15: required from here test.cpp:17:30: error: no matching function for call to ‘<lambda(int, int)>::__lambda0(int&, const int&)’ return Order(val, other.val); ^ test.cpp:17:30: note: candidates are: test.cpp:5:16: note: constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&) auto GoLess = [](int a,int b) -> bool ^ test.cpp:5:16: note: candidate expects 1 argument, 2 provided test.cpp:5:16: note: constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&) test.cpp:5:16: note: candidate expects 1 argument, 2 provided ``` Shouldn't this code work? Reading from those other threads in my understanding this code should compile, but is not. Thanks a lot Addendum: To clarify a little, in on of the above questions KennyTM wrote the following code: ``` auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; }; auto SetOfA = std::set <A, decltype(comp)> (comp); ``` Which should work, the second argument to std::set is a 'comparator' which in this case is a lambda, in my code I'm trying to do the same or at least i think i'm doing the same, but my code is not working. Something i missing in my code? Please note also from Xeo in Lambda expressions as class template parameters ``` auto my_comp = [](const std::string& left, const std::string& right) -> bool { // whatever } typedef std::unordered_map< std::string, std::string, std::hash<std::string>, decltype(my_comp) > map_type; ``` Again this should work. Where's my fault? Thanks

Original source

Related problems