简体   繁体   中英

Are there cases in which trailing-return-type syntax in lambda cannot be avoided?

关于前一个问题( 是否可以通过引用从lambda返回类型为T的对象而不使用尾随返回类型语法? ),我想知道是否有任何其他重要案例或示例,其中trailing-return-type语法,当使用lambdas时, 无法避免。

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM