2012-11-26 45 views
8

如果我有一個封裝了標準容器的模板,看來我可以合理輕易委託initializer_list的構造函數:可選支持initializer_list施工模板也許包裝容器

template<typename T> 
struct holder { 
    T t_; 

    holder() : 
     t_() {} 

    holder(std::initializer_list<typename T::value_type> values) 
     : t_(values) {} 

}; 

所以這個作品很好用的std ::矢量, 例如。

int main(int argc, char* argv[]) { 

    holder<std::vector<int>> y{1,2,3}; 
    return EXIT_SUCCESS; 
} 

但它顯然不適用於T作爲'int',或任何其他沒有嵌套的value_type typedef的類型。所以,我想使用某種enable_if或類似的技巧來使initializer_list構造函數不被釋放,除非T既定義了一個嵌套的value_type typedef,並且可以從std :: initializer_list構造。

我嘗試以下,但它仍然無法正常工作,因爲編譯器(鐺++ 3.1在我的情況),仍然形影不離,無效的T :: value_type的當T爲int:

holder(typename std::enable_if<std::is_constructible<T, std::initializer_list<typename T::value_type>>::value, std::initializer_list<typename T::value_type>>::type values) 
    : t_(values) {} 

任何關於如何表達「在T的value_type上給出此初始化列表構造函數上的模板的概念,當且僅當T具有value_type typedef並且可以從T :: value_type的initializer_list中構建」。

+0

是'initializer_list'按值傳遞正確,還是應該通過一些引用類型傳遞? ('&&'?) –

+0

@MartinBa:按值傳遞對於'std :: initializer_list'是正確的(並且推薦)。 –

+0

'initializer_list'只包含一個指針和一個大小,所以可以通過值傳遞它。數據本身不被複制。 –

回答

4

SFINAE只適用於模板參數置換(因此SFINAE中的S)。以下作品:

template<typename T> 
struct holder { 
    T t_; 

    holder() : 
     t_() {} 

    template<typename U = T> 
    holder(typename std::enable_if<std::is_constructible<U, std::initializer_list<typename U::value_type>>::value, 
    std::initializer_list<typename U::value_type>>::type values) 
    : t_(values) {} 

}; 

如果你沒有使用模板的功能,那麼整個類將被實例化的類型int(在你的例子),導致編譯器錯誤。

請注意,你可以讓函數簽名更好,如果你使用一個額外的模板參數:

template<typename U = T, class = typename std::enable_if<std::is_constructible<U, std::initializer_list<typename U::value_type>>::value, bool>::type> 
    holder(std::initializer_list<typename U::value_type> values) 
    : t_(values) {} 
+0

有趣,但它不太工作。使用我的原始版本'持有人> y = {1,2,3}'正常工作,但至少在我的編譯器中,它不適用於您的修訂構造函數簽名。它抱怨'候選構造模板不可行:需要1個參數,但提供了3個' – acm

+2

你不能刪除enable_if並只使用'template 持有者(std :: initializer_list 值)'? –

+0

@VaughnCato似乎更好。 – acm