【问题标题】:Why the standard preferred round brackets initialization for `make_<something>`?为什么 `make_<something>` 的标准首选圆括号初始化?
【发布时间】:2025-12-26 09:15:04
【问题描述】:

标准中的std::make_函数,如:

  • std::make_uniquestd::make_shared
  • std::make_tuple
  • std::make_from_tuple

所有内部都使用圆括号初始化而不是大括号

例如,make_from_tuple as presented by the standard 选择返回 T(params...) 而不是 T{params...}

结果如下是非法的:

auto vec = std::make_from_tuple<std::vector<int>>(std::make_tuple());
auto arr = std::make_from_tuple<std::array<int, 2>>(std::make_tuple(9, 8));

^ tuple 创建std::array,如上所述,是illegal also with C++20,因为p0960 - allowing initialization of aggregates from a parenthesized list of values 变为part of the C++20 spec 不允许对@ 进行此类初始化987654339@,因为它的内部类型是 T[size],它不能从值列表中初始化(括号已经被 std::array 初始化剥离)。


在它起作用的情况下,括号初始化与大括号的选择是有意义的:

auto vec2 = std::make_from_tuple<std::vector<int>>(std::make_tuple(2, 3));
// a vector with the values: {3, 3} surprise? :-)

(上面当然是玩具示例。提供的元组可以在外部提供)。

curly_make_from_tuple 喜欢:

template<typename T, typename tuple_t>
constexpr auto curly_make_from_tuple(tuple_t&& tuple) {
    constexpr auto get_T = [](auto&& ... x){ return T{std::forward<decltype(x)>(x) ... }; };
    return std::apply(get_T, std::forward<tuple_t>(tuple));
}

以上所有情况都可以,以一种人们可能认为更自然的方式:

auto arr = curly_make_from_tuple<std::array<int, 2>>(std::make_tuple(9, 8)); // {9, 8}
auto vec = curly_make_from_tuple<std::vector<int>>(std::make_tuple());       // {}
auto vec2 = curly_make_from_tuple<std::vector<int>>(std::make_tuple(2, 3));  // {2, 3}

问题是:为什么标准选择圆括号初始化而不是大括号


相关链接:

类似的问题,从效率的角度来看:Why does implementation of make_tuple not return via brace initialisation?

一个不错的discussion and suggestions for adding curly brackets initialization option for the `make_` utilities

提出make_from_tupleP0209r2的原始论文似乎没有讨论T(params...)T{params...}这两个替代方案,可能是因为所有类似的make_实用程序方法都已经使用圆括号初始化。

【问题讨论】:

  • 函数调用总是使用圆括号。这就是语言语法。大括号用于初始化列表。
  • 你问他们为什么使用T(std::forward&lt;decltype(x)&gt;(x) ... )而不是T{std::forward&lt;decltype(x)&gt;(x) ... }
  • @NathanOliver 是的,忽略支持两者的花哨选项(如最后提供的第二个链接中所述)如果应该支持一个,为什么要支持圆括号?
  • 不是初始化,是函数调用std::make_uniquestd::make_sharedstd::make_tuple等。不初始化东西,它们返回对象,它们的优点是线程安全,简单等。
  • @asmmo 问题在于这些函数的内部实现。

标签: c++ initialization stdtuple list-initialization


【解决方案1】:

因为在 C++98 中无法使用花括号初始化列表来初始化结构。

因此,为了保持一致性,新的标准库功能使用了与 STL 中使用的相同的初始化形式。

此外,出于兼容性原因,它从未更改为列表初始化:列表初始化不一定与等效的括号初始化形式具有相同的含义。

【讨论】:

  • 哪个库函数在 C++11 之前创建了这样的对象?可能没有,因为它依赖于可变参数模板。因此,如果所有这些函数都只出现在 C++11 或之后的版本中,它可能使用了大括号初始化。如果不使用一种花哨的方法来支持两者,当然必须选择一个,但委员会是否考虑了两者?这是一个有意的决定吗?
  • @AmirKirsh 例如 STL 分配器,用于复制构造。
最近更新 更多