2016-04-08 11 views
2

den folgenden Codeausschnitt Bitte beachten Sie:Überlastung der Plus-Operator für einen Satz von Klassen

template<class E> 
class vector_expression 
{}; 

template<class Tuple> 
class vector 
    : public vector_expression<vector<Tuple>> 
{}; 

template<class E1, class E2, class BinaryOperation> 
class vector_binary_operation 
    : public vector_expression<vector_binary_operation<E1, E2, BinaryOperation>> 
{ 
public: 
    vector_binary_operation(E1&& e1, E2&& e2, BinaryOperation op) 
     : m_e1(e1), m_e2(e2), 
      m_op(op) 
    {} 

private: 
    E1 m_e1; 
    E2 m_e2; 
    BinaryOperation m_op; 
}; 

template<class E1, class E2> 
vector_binary_operation<E1, E2, std::plus<>> operator+(E1&& e1, E2&& e2) { 
    return{ std::forward<E1>(e1), std::forward<E2>(e2), std::plus<>{} }; 
} 

Der obige Code dass vector_binary_operation speichert Verweise auf Objekte mit Namen und macht Kopien für Provisorien gewährleistet. Das Problem ist die Schnittstelle von operator+, weil es tatsächlich diesen Operator für jeden Typ definiert. Was muss ich ändern, wenn ich die Funktionalität beibehalten möchte, aber nur den Operator für Typen definieren möchte, die von vector_expression abgeleitet sind?

+1

Die Initialisiererliste in Ihrem Konstruktor sollte besser sein: 'm_e1 (std vorwärts (e1) ::), m_e2 (std :: vorwärts (e2)), m_op (std :: move (op)) '. Sonst bricht man die perfect-forwarding Kette. – davidhigh

+0

@davidhigh Ja, du hast Recht. Ich habe den Code von der anderen Frage kopiert, und dort waren die Parameter "e1" und "e2" konstante Referenzen. Danke, dass du das notiert hast. – 0xbadf00d

+0

Nein, ich liege falsch. Ich hätte Recht, wenn der Konstruktor eine Funktionsvorlage wäre, etwa so etwas wie "Vorlage Vektor_Binäroperation (E1 _ && e1, E2 _ && e2, BinäreOperation op)". Übrigens, das ist wahrscheinlich das, was Sie beabsichtigt haben, als Sie die '&&' verwendet haben. Weitere Informationen finden Sie unter [hier] (https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers) – davidhigh

Antwort

2

Sie könnten SFINAE und std::is_base_of auf folgende Weise verwenden:

template<class E1, class E2> 
std::enable_if_t<std::is_base_of_v<vector_expression<std::decay_t<E1>>, std::decay_t<E1>>&& 
       std::is_base_of_v<vector_expression<std::decay_t<E2>>, std::decay_t<E2>>, 
       vector_binary_operation<std::decay_t<E1>, std::decay_t<E2>, std::plus<>>> 
operator+(E1&& e1, E2&& e2) { 
    return { 
      std::forward<std::decay_t<E1>>(e1), 
      std::forward<std::decay_t<E2>>(e2), 
      std::plus<>{} 
      }; 
} 

Live Demo

+2

Benötigt 'Zerfall'. –

+0

@ T.C danke und es braucht viele von ihnen :). – 101010

+0

und es braucht viele "_t" Helfer, um den 'type T :: type' zu ​​verstecken – TemplateRex

1

@ 101010 gab bereits das Prinzip. Ich erweitere es ein wenig, wie Sie diese Frage auch in einem Kommentar von einem meiner answers gestellt haben.

Wie ich denke, Sie sind eine Überlastung mehr Operatoren als operator+, dann ist es zweckmäßig, eine Züge Klasse zu schreiben, die überprüft, ob alle bestanden Typen sind vector_expression s:

template<typename ... Ts> struct is_vector_expression 
    : public std::false_type {}; 
template<typename T> struct is_vector_expression<T> 
    : public std::is_base_of<vector_expression<std::decay_t<T> >, std::decay_t<T> >::type {}; 
template<typename T, typename ... Ts> struct is_vector_expression<T, Ts ...> 
    : public std::integral_constant<bool, is_vector_expression<T>::value 
             && is_vector_expression<Ts ...>::value> {}; 

Wenn C 17 ++ verwenden, können Sie auch überspringen die variadic Vorlage Sachen und verwenden std::conjunction.

Als nächstes können Sie, dass in einem geeigneten Alias ​​wickeln, so dass Sie sich std::enable_if_t die ganze Zeit nicht schreiben:

template<typename ... Ts> 
using enable_for_vector_expression = std::enable_if_t<is_vector_expression<Ts...>::value>; 

Schließlich können Sie verwenden, die wie im folgenden Beispiel für alle überlastet Betreiber:

template<typename E1, typename E2, 
     typename = enable_for_vector_expression<E1, E2> > 
auto operator+(E1&& e1, E2&& e2) 
{ 
    //... 
} 
+0

Wie würden Sie Ihr 'is_vector_expression'-Merkmal mit' std :: conjection' implementieren? – 0xbadf00d

+0

Vielleicht 'template \t \t mit enable_if_vector_expression_t = std :: enable_if_t >, std :: decay_t > ... >>; '? – 0xbadf00d

+0

@ 0xbadf00d: Ich würde es auf der Ebene von 'is_vector_expression' (und lassen Sie den Alias ​​wie es ist), aber ansonsten - nur in der Art, wie Sie geschrieben haben. – davidhigh

Verwandte Themen