2016-12-12 1 views
4

In Bezug auf eine frühere Anfrage (Is it possible to return an object of type T by reference from a lambda without using trailing return type syntax?), I gefragt, ob es einen anderer signifikanter Fall oder Beispiel ist, in der nachlauf return-Typ Syntax, wenn Lambdas verwenden, kann nicht vermieden werden.Gibt es Fälle, in denen die Syntax des schleppenden Rückgabetyps in Lambda nicht vermieden werden kann?

+5

Wenn Sie ein (temporäres) Objekt zurückgeben möchten, ohne einen Typ anzugeben. Wie 'return {a, b, c};' – SergeyA

+0

Wenn Sie einen Verweis auf ein Objekt zurückgeben möchten. – 0x499602D2

+1

@SergeyA Ich schrieb: kann ** nicht ** vermieden werden – FdeF

Antwort

4

In C++ 14, ein bisschen konstruiertes Beispiel ist die Verwendung von sfinae in Kombination mit einem allgemeinen Lambda:

[](auto &&arg) 
-> decltype(arg.f(), void()) 
{ /* do whatever you want */ } 

konnte man jedenfalls argumentieren, dass ein static_assert genügt:

[](auto &&arg) { 
    static_assert(has_metod_f<std::decay_t<decltype(arg)>>::value, "!"); 
    /* do whatever you want */ 
} 

Wo has_method_f ist das übliche Detektor-Idiom.
Wie auch immer, einen Fall vorstellen, wo Sie aus einer Reihe von lambdas Starten eines komponierten Funktors bauen wollen:

#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 diesem Fall wäre ein static_assert die Kompilierung verhindern, und es ist nicht das erwartete Ergebnis.
Auf der anderen Seite kann der nachfolgende Rückgabetyp verwendet werden, um sfinae direkt auf den Lambdas mit Hilfe ihrer Wrapper zu aktivieren.

4

Ich nehme an, dass ein anderer Fall ist, wenn es Typinkonsistenz zwischen differents gibt.

Ein dummes Beispiel

std::function<long(int)> f 
    = [](int v) -> long { if (v) return v; else return 0L; }; 

Offensichtlich Sie es, wenn Sie Inkonsistenzen vermeiden vermeiden kann, damit ich weiß nicht, ob es von Bedeutung ist.

+0

Nein, [Sie können es in Ihrem Fall vermeiden] (https://godbolt.org/g/dIwUrY). – skypjack

+3

@skypjack - rechts; genau was ich meine mit "Sie können es vermeiden, wenn Sie Inkonsistenz vermeiden"; nehmen Sie an, dass das Beispiel sehr sehr dumm ist. – max66

+1

Ich sehe, aber bitte lassen Sie mich sagen, dass es die Frage nicht beantwortet. Dies kann in diesem Fall leicht vermieden werden. – skypjack

Verwandte Themen