为什么std :: make_unique等人不存在std :: initializer_list重载?

时间:2016-05-11 10:58:15

标签: c++ c++11 c++-standard-library uniform-initialization

Should I use () or {} when forwarding arguments?foostd::vector克隆。

在N4140中,unique.ptr.create std::make_unique被指定为:

  

template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);

     
      
  • 备注:除非T不是数组,否则此函数不应参与重载决策。

  •   
  • 返回unique_ptr<T>(new T(std::forward<Args>(args)...))

  •   

这意味着需要使用()而不是{}来初始化对象。例如,以下

auto s1 = std::make_unique<foo>(3, 1).get()->size();
auto s2 = std::make_unique<foo>(1).get()->size();
auto s3 = std::make_unique<foo>(2).get()->size();
std::cout << s1 << s2 << s3;

输出312而如果使用{}(在std::make_unique内),则会输出211。由于无法推断初始化列表,因此必须显式传递std::initializer_list才能获得后者的结果。问题是,为什么不提供像这样的过载?

namespace test
{

template <class T, class Deduce>
std::unique_ptr<T> make_unique(std::initializer_list<Deduce> li)
{
    return ::std::make_unique<T>(li);
}

};

int main()
{
    auto p1 = test::make_unique<foo>({3, 1}).get()->size();
    auto p2 = test::make_unique<foo>({1}).get()->size();
    auto p3 = test::make_unique<foo>({2}).get()->size();
    std::cout << p1 << p2 << p3;
}

输出211

我不认为“你可以自己写”或“避免膨胀标准”的原因是非常好的理由。提供这种过载是否有任何缺点?

2 个答案:

答案 0 :(得分:2)

我不知道完整的历史,但最可能的答案是“没有人提出它”。

有证据证明std::make_unique仅在C ++ 14中添加,但{C} 11中存在std::unique_ptr

std::make_shared的代码和提案(最终在make_unique中镜像)在initializer_list之前存在(在boost中)以及支持它的初始化语法。

你现在可以做的一件事就是提出它(如果有的话,可以解决极端情况,例如,如果目标类型不支持initializer_list,请使用SFINAE去除重载)。 / p>

答案 1 :(得分:0)

我认为这只是一个模板扣除问题,请参阅this answer

你可以试试这些:

int main()
{
    auto p1 = std::make_unique<foo>(std::initializer_list<int>{3, 1}).get()->size();
    auto p2 = std::make_unique<foo>(foo{1}).get()->size();
    auto l3 = {2};
    auto p3 = std::make_unique<foo>(l3).get()->size();
    std::cout << p1 << p2 << p3;
}