(可选)支持模板的initializer_list构造,可能会包装容器

Optionally supporting initializer_list construction for templates maybe wrapping containers

本文关键字:构造 包装 list 支持 可选 initializer      更新时间:2023-10-16

如果我有一个包装标准容器的模板,似乎我可以合理地轻松地委派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 作为"int"或任何其他没有嵌套value_type typedef 的类型。所以,我想使用某种enable_if或类似的技巧来使initializer_list构造函数不被发出,除非 T 都定义了嵌套的 value_type typedef,并且可以从 std::initializer_list 构造。

我尝试了以下内容,但它仍然不起作用,因为当 T 为 int 时,编译器(在我的情况下为 clang++ 3.1)仍然会绊倒无效的 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 的value_type上给这个模板一个初始值设定项列表构造函数,当且仅当 T 具有 value_type typedef 并且可以从 T::value_type 的initializer_list构造"。

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