问题
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.
回答1:
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.
回答2:
I suppose that another case is when there is type inconsistency between differents returns.
A silly example
std::function<long(int)> f
= [](int v) -> long { if ( v ) return v; else return 0L; };
Obviously you can avoid it if you avoid inconsistency so I don't know if it's significant.
来源:https://stackoverflow.com/questions/41105454/are-there-cases-in-which-trailing-return-type-syntax-in-lambda-cannot-be-avoided