2017-12-27 3 views
3

Ich würde gerne verstehen, wie Ableitungen mit universellen Referenzen und std::forward arbeiten, insbesondere um perfekt Weiterleitung Wrapper zu erstellen. Der folgende Code enthält einen Code zum Experimentieren mit einem Funktor-Wrapper in zwei Fällen: einen mit einem impliziten Deduktionsleitfaden und einen mit einem expliziten Deduktionsleitfaden.Perfekte Weiterleitung mit Klasse Vorlage Argument Abzug

Ich habe eine Menge && und std::forward in Kommentare eingefügt, weil ich nicht weiß, wo sie benötigt werden, um eine perfekte Weiterleitung zu erreichen. Ich würde gerne wissen, wo ich sie hinstellen soll und wo sie nicht benötigt werden.

// Case with not conversion constructor 
template <class F> 
struct functor1 
{ 
    explicit constexpr functor1(F/*&&*/ f) 
    noexcept(std::is_nothrow_copy_constructible_v<F/*&&*/>) 
    : _f(/*std::forward<F>(*/f/*)*/) 
    {} 
    template <class... Args> 
    constexpr operator()(Args&&... args) 
    noexcept(std::is_nothrow_invocable_v<F/*&&*/, Args/*&&*/...>) 
    { 
     /*std::forward<F>(*/_f/*)*/(std::forward<Args>(args)...); 
    } 
    private: F/*&&*/ _f; 
}; 

// Case with a conversion constructor 
template <class F> 
struct functor2 
{ 
    template <class G> 
    explicit constexpr functor2(G&& g) 
    noexcept(std::is_nothrow_constructible_v<G/*&&*/, F/*&&*/>) 
    : _f(/*std::forward<G>(*/g/*)*/) 
    {} 
    template <class... Args> 
    constexpr operator()(Args&&... args) 
    noexcept(std::is_nothrow_invocable_v<F/*&&*/, Args/*&&*/...>) 
    { 
     /*std::forward<F>(*/_f/*)*/(std::forward<Args>(args)...); 
    } 
    private: F/*&&*/ _f; 
}; 
template <class G> 
functor2(G&&) -> functor2<G/*&&*/>; 

EDIT: Aus Gründen der Einfachheit, und weil es nicht der Punkt der Frage ist, in den vorhergehenden Beispielen, betrachten wir, dass F und G sind Funktion dh Klassen/Strukturen mit einem operator() Objekte.

Antwort

1

Im C++ - Standard definiert der Begriff Forwarding-Referenz. Eine Annahme universelle Referenz wird als Synonym für diesen Begriff verwendet. [temp.deduct.call]/3

A Forwarding Referenz ist eine rvalue Bezugnahme auf einen CV-unqualifizierten Template-Parameter, der nicht einen Template Parameter einer Klassenvorlage darstellt.

anwenden Dieses Konzept nur auf Template-Funktion Argument oder eine Vorlage Konstruktorargument. In allen anderen Fällen ist T&& ein rvalue Referenz. Das Konzept der Weiterleitungsreferenz ist nur nützlich für Vorlage Argumentabzug.

//possibilities of argument deduction, [cv] means any combination of "const" and "volatile": 
// <"","const","volatile","const volatile"> 
template<class T> void f(T&); 
    //4 possibilities: void f([cv] int&); 

template<class T> void f(const T&); 
    //2 possibilities: void f(const int&); 
        //void f(const volatile int&); 

template<class T> void f(T&&); 
    //Forwarding reference, 8 possibilities 
      //void f([cv] int&); 
      //void f([cv] int&&); 

template<class T> void f(const T&&); 
    //NOT a forwarding reference because of the const qualifier, 2 possibilities: 
      //void f(const int&&); 
      //void f(const volatile int&&); 

template<class T> 
struct S{ 
    template<class U> 
    S(U&&); 
     //Forwarding reference, 8 posibilities: 
      //void S<X>([cv] int&); 
      //void S<X>([cv] int&&); 
     //no template argument deduction posible 

    S(T&&); 
     //NOT a forwarding reference, 1 possibility: 
      //void S<X>(X&&); 
     //Generated argument deduction: 
     //template<class T> S(T&&) -> S<T>; 
      //not a forwarding reference because T is a parameter of the template class; 
      //=> 4 possibilities: -> S<[cv] int&&> 


    T&& a; //an rvalue reference if T is [cv] int or [cv] int&&, 
      //an lvalue reference if T is [cv] int&; 
      //This comes from reference colapsing rules: &+&=&; &&+&=&; &&+&&=&&  //(Nota: You may consider that a rvalue reference data member is probably a mistake) 
}; 

template<class U> 
S(U&&) -> S<U&&>; 
//Forwarding reference, 8 possibilities: 
// S<[cv] int&>; 
// S<[cv] int&&>; 

Mit std::forward Sinn im Inneren des Körpers eines nur: Lassen Sie uns das in den folgenden Beispielen prüfen, alle fonctions und Konstrukteure sind mit einem int Argument (unabhängig von seiner Konstantheit und Wertkategorien (L-Wert/R-Wert) genannt Funktion oder ein Konstruktor, wenn das Argument std::forward entweder eine rvalue-Referenz oder eine lvalue-Referenz sein kann, je nach Vorlagenargumentabzug und kollabierenden Referenzregeln.Wenn das Argument std::forward immer eine rvalue-Referenz ergibt, wird std::move bevorzugt, und zwar immer ergibt sich eine L-Wert-Referenz, nichts ist bevorzugt

Verwandte Themen