如何使用构造函数设计带有std :: initializer_list的类?

Emi*_*ier 7 c++ vector initializer-list c++11

当类具有构造函数重载时std::initializer_list,即使其他构造函数重载看起来更好匹配,此重载也将优先.这个问题在Sutter的GotW#1,第2部分以及Meyers的Effective Modern C++,Item 7中有详细描述.

这个问题表现出来的典型例子是大括号初始化std::vector:

std::vector<int> vec{1, 2};
// Is this a vector with elements {1, 2}, or a vector with a single element 2?
Run Code Online (Sandbox Code Playgroud)

Sutter和Meyers都建议避免类设计,其中initializer_list构造函数重载可能会给程序员带来歧义.

萨特:

准则:当你设计一个类时,避免提供一个使用initializer_list构造函数模糊地重载的构造函数,这样用户就不需要使用()来访问这样一个隐藏的构造函数.

迈尔斯:

因此,最好设计构造函数,以便调用的重载不受客户端是否使用括号或大括号的影响.换句话说,从std :: vector接口设计中的错误中学习,并设计类来避免它.

但他们都没有描述应如何 vector设计以避免这个问题!

所以这是我的问题:应该如何vector设计以避免initializer_list构造函数重载的模糊(不丢失任何功能)?

Bar*_*rry 8

我会采取标准带着同样的方法piecewise_constructpairdefer_lockunique_lock:使用在构造标签:

struct n_copies_of_t { };
constexpr n_copies_of_t n_copies_of{};

template <typename T, typename A = std::allocator<T>>
class vector {
public:
    vector(std::initializer_list<T>);
    vector(n_copies_of_t, size_type, const T& = T(), const A& = A());
    // etc.
};
Run Code Online (Sandbox Code Playgroud)

那样:

std::vector<int> v{10, 20}; // vector of 2 elems
std::vector<int> v2(10, 20); // error - not a valid ctor
std::vector<int> v3(n_copies_of, 10, 20); // 10 elements, all with value 20.
Run Code Online (Sandbox Code Playgroud)

另外,我总是忘记它是10个元素值20或20个元素值10,所以标签有助于澄清这一点.

  • 有没有理由在前面贴上标签?(也许,为了与具有参数包的函数保持一致?)如果没有,为什么不`vector(size_type,copies_of_t,T const&);`?(顺便说一句,C++ 11删除了`const value_type&`的默认参数,可能是因为你可以编写一个ctor值,初始化N个元素而不需要复制性.) (3认同)