可选地支持模板的initializer_list构造可能包装容器

acm*_*acm 10 c++ templates initializer-list enable-if c++11

如果我有一个包装标准容器的模板,似乎我可以合理地轻松委托initializer_list构造函数:

template<typename T>
struct holder {
    T t_;

    holder() :
        t_() {}

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

};
Run Code Online (Sandbox Code Playgroud)

因此,这与std :: vector很好地配合.

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

    holder<std::vector<int>> y{1,2,3};
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

但它很明显不适用于T作为'int',或任何其他没有嵌套value_type typedef的类型.所以,我想使用某种enable_if或类似技巧来使initializer_list构造函数不被发出,除非T都定义了嵌套的value_type typedef,并且可以从std :: initializer_list构造.

我尝试了下面这个,但它仍然不起作用,因为编译器(在我的情况下是clang ++ 3.1),当T为int时仍会跳过无效的T :: value_type:

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) {}
Run Code Online (Sandbox Code Playgroud)

关于如何表达概念的任何想法"在T的value_type上给这个模板提供初始化列表构造函数,当且仅当T具有value_type typedef且可从T :: value_type的initializer_list构造时".

mfo*_*ini 5

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) {}

};
Run Code Online (Sandbox Code Playgroud)

如果您没有使用模板函数,那么将为该类型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) {}
Run Code Online (Sandbox Code Playgroud)

  • 难道你不能删除enable_if并只使用`template <typename U = T> holder(std :: initializer_list <typename U :: value_type> values)`? (2认同)