In relation to a previous question (Is it possible to return an object of type T by reference from a lambda without using trailing return type syntax?), I was wondering if there is any other significant case or example in which trailing-return-type syntax, when using lambdas, can not be avoided.
In C++14, a bit contrived example is the use of sfinae in combination with a generic lambda:
[](auto &&arg)
-> decltype(arg.f(), void())
{ /* do whatever you want */ }
Anyway one could argue that a static_assert
suffices:
[](auto &&arg) {
static_assert(has_metod_f<std::decay_t<decltype(arg)>>::value, "!");
/* do whatever you want */
}
Where has_method_f
is the common detector idiom.
Anyway, imagine a case where you want to construct a composed functor starting from a bunch of lambdas:
#include<utility>
#include<iostream>
template<typename...>
struct Base;
template<typename Func, typename... Others>
struct Base<Func, Others...>: Func, Base<Others...> {
Base(Func func, Others... others)
: Func{std::move(func)}, Base<Others...>{std::move(others)...}
{}
template<typename... Args>
auto operator()(int, Args&&... args)
-> decltype(Func::operator()(std::forward<Args>(args)...)) {
Func::operator()(std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(char, Args&&... args) {
Base<Others...>::operator()(0, std::forward<Args>(args)...);
}
};
template<>
struct Base<> {
template<typename... Args>
auto operator()(Args&&...) {
std::cout << "fallback" << std::endl;
}
};
template<typename... Ops>
struct Mixin: Base<Ops...> {
Mixin(Ops... ops)
: Base<Ops...>{std::move(ops)...}
{}
template<typename... Args>
auto operator()(Args&&... args) {
return Base<Ops...>::operator()(0, std::forward<Args>(args)...);
}
};
struct T { void f() {} };
struct U {};
int main() {
auto l1 = [](auto &&arg) -> decltype(arg.f(), void()) {
std::cout << "accept T" << std::endl;
};
auto l2 = [](U) {
std::cout << "accept U" << std::endl;
};
Mixin<decltype(l1), decltype(l2)> mixin{std::move(l1), std::move(l2)};
mixin(T{});
mixin(U{});
mixin(0);
}
In this case, a static_assert
would prevent the compilation and it is not the expected result.
On the other side, the trailing return type can be used to enable sfinae directly on the lambdas with the help of their wrappers.
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