标准中的std::make_
函数,例如:
std::make_unique
和std::make_shared
std::make_tuple
std::make_from_tuple
都使用内部圆括号初始化而不是大括号。
例如,标准中提出的make_from_tuple
是选择返回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
也是非法的,因为 C++20 也是非法的,因为 p0960 - 允许从括号中的值列表初始化聚合成为 C++20 规范的一部分不允许对std::array
进行这样的初始化,因为它的内部类型是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}
问题是:为什么标准选择圆括号初始化而不是大括号?
相关链接:
类似的问题,从效率的角度来看:为什么make_tuple的实现不会通过大括号初始化返回?
为"make_"实用程序添加大括号初始化选项的很好的讨论和建议。
提出make_from_tuple
的原始论文P0209r2似乎没有讨论T(params...)
和T{params...}
两种选择,可能是因为所有类似的make_
实用程序方法都已经使用了圆括号初始化。
因为在 C++98 中使用大括号初始化列表无法初始化结构。
因此,为了保持一致性,新的标准库功能使用了与 STL 中使用的初始化形式相同的初始化形式。
此外,出于兼容性原因,它从未更改为列表初始化:列表初始化不一定与等效的括号初始化形式具有相同的含义。