I want to use a lambda to evaluate (switch-case) some conditions and return a lambda accordingly.
const auto lmb1 = []() {
printf("1\n");
};
const auto lmb2 = []() {
printf("2\n");
};
const auto select = [](auto const &ref) {
switch(ref) {
case 1: return lmb1;
case 2: return lmb2;
}
};
std::function foo = select(1);
foo();
Sadly things aren't working.
What I am doint wrong?
The problem is that a lambda, by default, deduce (as an auto
function) the returned type and in your lambda you return two different lambdas. Every lambda has a different type, so the compiler can't choose a type for the returned lambda
[](auto const &ref) {
switch(ref) {
case 1: return lmb1; // decltype(lmb1)
case 2: return lmb2; // != decltype(lmb2)
}
};
You can solve the problem in different ways.
You can explicit the lambda returned type, using a type that both lmb1
and lmb2
can be converted to (in this example, std::function<void()>
or also void(*)()
). When that type is available
// -----------------vvvvvvvvvvvvvvvvvvvvvvvv
[](auto const &ref) -> std::function<void()> {
switch(ref) {
case 1: return lmb1;
case 2: return lmb2;
}
};
You can explicitly convert the returned values to a common type. Again: when a common type is available
[](auto const &ref)
{
switch(ref) { // --V
case 1: return +lmb1; // with the '+', lmb1 is converted to a void(*)()
case 2: return +lmb2; // with the '+', lmb2 is converted to a void(*)()
} // --------------^
If the ref
argument can be a template value, starting from c++20 you can define a template lambda and, using if constexpr
, you can return different types from different lambdas. This works also when there isn't a common type (but require a compile-time known argument)
const auto selct = []<int REF>(std::integral_constant<int, REF>) {
if constexpr ( 1 == REF )
return lmb1;
else
return lmb2;
};
auto foo = selct(std::integral_constant<int, 1>{});