2016-04-14 16 views
1

Im folgenden Code kompiliert der Aufruf der Memberfunktion F von Instanz b mit Argument {1,2} und ruft B::F(std::initializer_list<int>) auf. Aber wenn ich ein Element aus der verspannten-init-Liste entfernen und verwenden nur {1}, bekomme ich einen FehlerWarum wird der Typ der stained-init-Liste mit einem Element auf den Typ des Elements selbst umgeschaltet?

9 : error: no matching function for call to 'begin(int)' using type = decltype(std::begin(std::declval<T>()));

Ich verstehe nicht, warum der Compiler für begin(int) sucht, und nicht begin(initializer_list<int>)

Ich habe mit diesem bei https://godbolt.org/g/tMyYQs gespielt, und ich bekomme die gleiche Art von Fehler sowohl in Clang und G ++. Was vermisse ich?

#include <type_traits> 
#include <iterator> 

template< bool B, class T = void > 
using enable_if_t = typename std::enable_if<B,T>::type; 

template <typename T> 
struct mytrait { 
    using type = decltype(std::begin(std::declval<T>())); 
    }; 

template <typename T> 
class A { 
    public: 
    template <typename TA, typename = 
    enable_if_t<std::is_same<T, typename mytrait<TA>::type>::value>> 
     A(TA &&){} 
}; 

class B 
{ 
    public: 
    void F(A<int>); 
    void F(std::initializer_list<int>); 
}; 

int main() 
{ 
    B b; 

    b.F({1,2}); // compiles fine 
#if 0 
    b.F({1});  // causes mytrait<int>::type to be examined, 
       // not mytrait<std::initializer_list<int>>::type 
#endif 
} 
+1

Wegen "einheitlicher Initialisierung" :-) –

Antwort

1

In Ordnung, ich denke, ich habe es herausgefunden. Wenn der Compiler b.F({1}) sieht, versucht er herauszufinden, welche Überladung von F zu rufen ist. Es sieht, dass es eine Überlastung gibt, die eine A<int>, also über copy-list-initialization, versucht, um zu sehen, ob es eine A<int> mit A<int>{1} erstellen kann. Der Typ des Literals 1 ist int. Also wird TA zu int abgeleitet. mytrait<int> versucht, decltype(std::begin(declval<int>())) zu ermitteln, gibt es keine std :: begin für Typ int, also die Compilerfehler.

Für b.F({1,2}) gibt es keinen Konstruktor von A<int>, der zwei Eingänge akzeptiert, so dass die Initialisierung der Liste nicht einmal versucht wird.

Es sieht aus wie ich meine mytraits Template-Deklaration beheben

template <typename T, typename = decltype(std::begin(std::declval<T>()))> 
struct mytraits {...}; 

dies durch eine Änderung das scheint SFINAE zu verwenden mytrait < int> :: Typ sein, eine Substitution Ausfall zu machen.