2016-04-14 36 views
1

在下面的代碼中,使用參數{1,2}對實例b的成員函數F進行編譯並調用B::F(std::initializer_list<int>)。但是,如果我從支撐-初始化列表中刪除一個元素,並使用剛剛{1},我得到一個錯誤爲什麼帶有一個元素的braced-init-list類型切換到元素本身的類型?

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

我不明白爲什麼編譯器正在尋找begin(int),而不是begin(initializer_list<int>)

我一直在玩這個https://godbolt.org/g/tMyYQs,我在clang和g ++上都得到了同樣的錯誤。我錯過了什麼?

#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

由於「統一初始化」:-) –

回答

1

好吧,我想我想通了。當編譯器看到b.F({1})它試圖找出F調用哪個超載。它看到有一個過載需要A<int>,因此,通過copy-list-initialization,它試圖查看它是否可以使用A<int>{1}構造A<int>。文字1的類型是int。所以TA被推斷爲int。 mytrait<int>試圖確定decltype(std::begin(declval<int>())),int類型沒有std :: begin,所以編譯器錯誤。

對於b.F({1,2}),沒有構造函數A<int>接受兩個輸入,所以甚至不嘗試列表初始化。

它看起來像我可以改變我的mytraits模板聲明解決這個問題,以

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

,這似乎是使用SFINAE使mytrait < INT> ::類型是置換失敗。