Hello! I'm sorry, I'm very new to C++, so the question can be very silly. So, sorry about it, but I failed to answer on my own. So!
I have a function that receives a lambda:
1 2 3 4
|
template <typename Λ>
auto call(Λ λ) -> decltype(λ()){
return λ();
}
|
What I want is two have 2 different functions: for lambdas that return a value and for lambdas - that do not. So another overload would look like (pseudocode):
1 2 3 4
|
template <typename Λ>
auto call(Λ λ) -> decltype(λ()) == void{
λ();
}
|
Okay, my the next though - is to use SFINAE to achieve that. Honestly, I've never used SFINAE before, so I failed:
1 2 3 4 5 6 7 8 9 10 11
|
template <typename Λ>
auto call(Λ λ) -> decltype(λ()) {
static_assert(! std::is_same<decltype(λ()), void>(), "This overload can return a value of any type");
return λ();
}
template <typename Λ>
void call(Λ λ) {
static_assert( std::is_same<decltype(λ()), void>(), "This overload returns void");
λ();
}
|
It even compiles! But, let's test it:
1 2
|
cout << call([] { return 1; }) << endl;
call([] { 2 * 2; });
|
These two `call` calls are ambiguous (at least, in MS VS). I can't understand why - I'm using static_assert, so the call should not be ambiguous. If you can, please, explain me the situation.
Then, I tried another way:
1 2 3 4 5 6 7 8 9 10
|
template <typename Λ>
auto call(Λ λ) -> decltype(λ()){
using namespace std;
if (!is_same<decltype(λ()), void>()) {
return λ();
} else {
cout << "Just do some work!" << endl;
}
}
|
Suddenly, it works. I understand, that, roughly, it compiles to:
1 2 3 4 5 6 7
|
void call(Λ λ) {
if (false) {
return λ();
} else {
cout << "Just do some work!" << endl;
}
}
|
and, for example:
1 2 3 4 5 6 7
|
int call(Λ λ) {
if (true) {
return λ();
} else {
cout << "Just do some work!" << endl;
}
}
|
So, everything is correct, though, for some reasons, I don't like this approach. It looks more like a workaround, not like a real solution. But what would you do? Also, I wonder, what should I do, if I need to add overloads, that depend on lambda-parameters. For instance, it works:
1 2 3
|
void call(function<void(int, int) f){ ... }
void call(function<void(int) f){ ... }
void call(function<void(void) f){ ... }
|
But I don't want to have run-time penalty, because of using std::function! :)