10

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

template<typename T>
struct holder {
    T t_;

    holder() :
        t_() {}

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

};

例如,这可以很好地与 std::vector 一起使用。

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

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

但它显然不适用于 T as '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) {}

关于如何表达概念的任何想法“给 T 上的这个模板一个基于 T 的 value_type 的初始化列表构造函数,当且仅当 T 具有 value_type typedef 并且可以从 T::value_type 的 initializer_list 构造”。

4

1 回答 1

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

};

如果您没有使用模板函数,那么整个类将被实例化为该类型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) {}
于 2012-11-26T15:00:31.697 回答