2015-01-14 15 views
8

Nota: questa domanda è molto simile a Return type deduction for in-class friend functions, ma non ho trovato la risposta al mio problema.Funzione amico modello e deduzione tipo di reso

testato con clangore 3.4 con std = C++ 1A e Clang 3.5 con std = C++ 14 e std = C++ 1Z

Questo codice compila:

#include <iostream> 

template<class T> 
class MyClass { 
    public: 
     MyClass(T const& a) : impl(a) {} 

     template<class T0, class T1> friend auto 
     // requires operator+(T0,T1) exists 
     operator+(MyClass<T0> const& a, MyClass<T1> const& b) 
     { 
      return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl}; 
     } 

     T getImpl() const { return impl; } 

    private: 
     T impl; 
}; 

int main() { 
    MyClass<int> x(2); 
    MyClass<long> y(2); 

    auto z = x+y; 
    std::cout << z.getImpl() << "\n"; 
} 

Ora, se io definire operatore + al di fuori della classe, che non può essere compilato più:

template<class T> 
class MyClass { 
    public: 
     MyClass(T const& a) : impl(a) {} 

     template<class T0, class T1> friend auto 
     operator+(MyClass<T0> const& a, MyClass<T1> const& b); 

     T getImpl() const { return impl; } 
    private: 
     T impl; 
}; 

template<class T0, class T1> auto 
operator+(MyClass<T0> const& a, MyClass<T1> const& b) 
{ 
    return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl}; 
} 

Clang 3.4 dice:

error: use of overloaded operator '+' is ambiguous (with operand types MyClass<int> and MyClass<long>) 

E poi indica ciò che ritiene essere due funzioni diverse: la dichiarazione nella classe e la definizione al di fuori della classe.

La mia domanda è: è un bug di clang o solo che i parametri del template sono dedotti per una funzione di amico, quindi le due funzioni che non sono equivalenti sono alcuni casi? E quale alternativa suggeriresti: rendere operatore + una funzione membro, o definire l'operatore amico + all'interno della classe (quale sarebbe a mio parere ingombrare l'interfaccia di classe)?

Solo per vostra informazione, ho un caso di utilizzo reale di tale codice, in cui cerco di avvolgere una classe di terza parte e ho bisogno di una deduzione di tipo restituito a causa dell'uso del modello di espressione per la valutazione lazy.

Edit: Il seguente funziona (ma ancora ingombra l'interfaccia ...)

template<typename T> 
class MyClass 
{ 
    T impl; 

public: 
    explicit MyClass(T a) : impl(std::move(a)) { } 

    T const& getImpl() const { return impl; } 

    template<typename T0, typename T1> 
    friend auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)>; 
}; 

template<typename T0, typename T1> 
auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)> 
{ 
    return MyClass<decltype(a.impl + b.impl)>(a.impl + b.impl); 
} 
+1

non ho letto C++ 14 ancora, ma è 'auto' senza un tipo di ritorno finale effettivamente accettati non definente funzione dichiarazioni? – Angew

+0

Non so cosa dice lo standard, ma clang lo accetta, almeno per le funzioni membro. Penso che sia correlato al fatto che non puoi sovraccaricare in base al tipo di reso. –

+0

L'opposto accade quando ho provato VS 2015. Il primo non funziona con "errore C2995: 'operatore automatico + (const MyClass &, const MyClass &)': il modello di funzione è già stato definito" e il secondo viene compilato ed eseguito. Sembra che VS duplichi il membro se è incorporato, causando due definizioni di 'operator + '. – Guvante

risposta

1

edit: un'occhiata alla sezione commenti, si tratta di un bug in gcc 4.8.2 e 4.9

Gcc codice di errore:

prog.cpp:10:61: error: non-static data member declared 'auto' operator+(MyClass const& a, MyClass const& b) ^prog.cpp: In function 'int main()': prog.cpp:25:15: error: no match for 'operator+' (operand types are 'MyClass' and 'MyClass') auto z = x+y; ^

+4

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59766 – dyp

+0

Sì, ma qual è il problema? operator + (MyClass) e operatore + (MyClass , MyClass ) hanno diverse firme. Possono quindi restituire valori diversi –

+0

Anche il messaggio Gcc è strano, perché MyClass non è un tipo, ma un modello. –

Problemi correlati