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
Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.
Permalink. All the alternatives to passing a lambda by value actually capture a lambda's address, be it by const l-value reference, by non-const l-value reference, by universal reference, or by pointer.
Inlinable lambdas can only be called inside inline functions or passed as inlinable arguments. noinline lambdas, however, can be manipulated in any way you like, including being stored in fields or passed around.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With