2017-07-10 3 views
4

Ist es möglich, class template argument deduction für eine Klasse C aus der Definition einer der C Mitgliederfunktionen zu verwenden? ... oder bin ich gezwungen, meine make_c Hilfsklasse wie in C++ 03 zu schreiben?Vorlage Argument Typ Abzug aus innerhalb der Klassendefinition

Betrachten Sie diese minimiert und vereinfachte Szenario, das eine Kette von beliebigen Funktionsobjekte baut:

template <typename F> 
struct node; 

template <typename FFwd> 
node(FFwd&&) -> node<std::decay_t<FFwd>>; 

Die node Klasse speichert ein Funktionsobjekt, das über perfekte Weiterleitung initialisiert wird. Ich brauche einen Deduktion Guide hier zu decay den Typ der Funktion Objekt.

template <typename F> 
struct node 
{ 
    F _f; 

    template <typename FFwd> 
    node(FFwd&& f) : _f{std::forward<FFwd>(f)} 
    { 
    } 

    template <typename FThen> 
    auto then(FThen&& f_then) 
    { 
     return node{[f_then = std::move(f_then)] 
        { 
         return f_then(); 
        }}; 
    } 
}; 

Danach definiere ich node ‚s Konstruktor und eine Fortsetzungs .then Elementfunktion, die einen neuen Knoten zurückgibt (seine Implementierung ist unsinnig, die Größe des Beispiels zu minimieren). Wenn ich .then aufzurufen versuchen ...

auto f = node{[]{ return 0; }}.then([]{ return 0; }); 

... Ich erhalte einen unerwarteten Kompilierungsfehler:

prog.cc: In instantiation of 'node<F>::node(FFwd&&) [with FFwd = node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]::<lambda()>; F = main()::<lambda()>]': 
prog.cc:27:22: required from 'auto node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]' 
prog.cc:35:56: required from here 
prog.cc:17:46: error: no matching function for call to 'main()::<lambda()>::__lambda1(<brace-enclosed initializer list>)' 
    node(FFwd&& f) : _f{std::forward<FFwd>(f)} 
              ^
prog.cc:35:20: note: candidate: 'constexpr main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 
    auto f = node{[]{ return 0; }}.then([]{ return 0; }); 
        ^

live example on wandbox

Dies geschieht, weil im Innern des Körper von node<F>::then, node{...} schafft eine Instanz mit dem Typ *this - es löst keinen Argumenttyp Abzug aus. Ich bin daher gezwungen zu schreiben:

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    auto l = [f_then = std::move(f_then)]{ return f_then(); }; 
    return node<std::decay_t<decltype(l)>>{std::move(l)}; 
} 

live example on wandbox

..., die den ganzen Zweck des Abzugs Führer besiegt.

Gibt es einen Weg, ich kann Klassenvorlage Argument Abzug hier ohne Einführung Code Repetition oder eine make_node Funktion?

Antwort

6

Die Namenssuche für node fand den injizierten-Klasse-Namen, von dem Abzug nicht durchgeführt. (In diesem Fall wäre Abzug eine Abwärtskompatibilitätspause gewesen.)

Wenn Sie einen Abzug wünschen, qualifizieren Sie den Namen so, dass Sie das Namespacemitglied finden.

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    return ::node{[f_then = std::move(f_then)] 
    //  ^^ 
       { 
        return f_then(); 
       }}; 
} 

Auch ein sauberer Weg, um die Führung ist

template <typename F> 
node(F) -> node<F>; 
+0

Duh, ich hatte das Gefühl, ich einfach etwas fehlte zu schreiben. Prost. Wird so bald wie möglich annehmen. –

+0

Ist das Verfallen des Typs im Deduktionsleitfaden nutzlos? Oder wofür ist der "cleaner guide"? –

+0

@ MárioFeroldi Wenn der Guide das Argument durch Weiterleiten der Referenz übernimmt, müssen Sie den Typ manuell dekadieren (für den Anwendungsfall im OP). Wenn es das Argument nach Wert nimmt, dann macht die Sprache den Zerfall für Sie und Sie müssen es nicht manuell zerlegen. –

0

Ich fand eine mögliche Lösung, aber es erfordert eine externe Implementierung einer make Funktion.

Gute Nachrichten: es muss nicht sein make_node - es kann mit jedem Typ T, die Klasse Vorlage Argument Abzug unterstützt.

template <template <typename...> class T, typename... Ts> 
auto make(Ts&&... xs) 
    noexcept(noexcept(T{std::forward<Ts>(xs)...})) 
    -> decltype(T{std::forward<Ts>(xs)...}) 
{ 
    return T{std::forward<Ts>(xs)...}; 
} 

Verbrauch:

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    return make<node>([f_then = std::move(f_then)] 
        { 
         return f_then(); 
        }); 
} 
Verwandte Themen