Let's assume we have the following lambda declared in the global namespace:
auto Less = [](int a,int b) -> bool
{
return a < b;
}
And the following code which make use of this lambda:
template<typename T>
struct foo
{
foo(int v){}
bool operator<(const foo<T>&) const
{
return T(1,2);
}
};
int main()
{
typedef foo<decltype(Less)> be_less;
priority_queue<be_less> data;
}
As you can see I use Less
as template parameter for the struct foo
. With g++4.9.2 this code does not compile:
test1.cpp:13:21: error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
return T(1,2);
^
test1.cpp:13:21: note: candidates are:
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
auto Less = [](int a,int b) -> bool
^
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
Bu I may fix this problem adding two small changes, first of all I need to change the lambda into this:
bool Less = [](int a,int b) -> bool
{
return a < b;
}
As you can see i just replaced auto
with bool
, this modification alone still does not work:
test1.cpp:13:21: error: expression list treated as compound expression in functional cast [-fpermiss
ive]
return T(1,2);
Unless I add -fpermissive
, or i may change the operator<
bool
in this way:
bool operator<(const foo<T>&) const
{
return T((1,2));
}
Note the double parentheses. Now the code compile and everything work.
My question is, which is the technical reason why auto Less
does not work but bool Less
work?
I believe I know why the double parentheses are required in the second operator<
, this should be to avoid the compiler to interpret T(1,2)
as a declaration instead of a call.
Thanks for your time
In your first example you're constructing foo<T>
where [T = decltype(Less)]
. So in this expression
return T(1,2);
you're trying to construct an instance of the lambda by invoking a constructor that takes 2 int
s, which obviously doesn't exist. That's exactly what the error message is telling you
error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
The only constructors that exist are the copy and move constructors for the lambda (the closure type created from a lambda expression is not default constructible), which the compiler tries to match the arguments against and fails
constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
candidate expects 1 argument, 2 provided
In the second case, by making this change
bool Less = [](int a,int b) -> bool
{
return a < b;
};
what you've done is declare a boolean variable named Less
and initialize it to true
.
This is because the lambda expression you have is capture-less, which means it can be implicitly converted into a pointer to a function that takes the same arguments as the lambda's operator()
and returns the same type as the original lambda. So you convert the lambda expression to bool(*)(int,int)
.
Next, a function pointer is implicitly convertible to bool
and will always evaluate to true
(assuming it actually points to the address of a function, which it does here). So Less
gets initialized to true
.
Now, decltype(Less)
is nothing but bool
. So here you're trying a function style cast to bool
, but passing in 2 arguments
return T(1,2);
Hence the error
error: expression list treated as compound expression in functional cast
By adding the extra parentheses you have an expression consisting of 2 sub-expressions separated by the comma operator. This will evaluate and discard the first sub-expression (1
) and return the value of the second (2
) which is then cast to bool
, so it converts to true
.
I'm not really sure what you're attempting to do to be able to suggest a solution, but if all you want is define some comparison predicate for foo
that'll then be invoked by the priority_queue
, then maybe the following works?
struct foo
{
foo(int v) {}
};
auto Less = [](foo const& a, foo const& b) -> bool
{
return true; // do whatever comparison you need
};
int main()
{
using my_priority_queue = std::priority_queue<foo, std::vector<foo>, decltype(Less)>;
my_priority_queue data(Less); // pass a copy of the comparator
}
Live demo
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