经过一些调查,看起来初始化变量的行为遵循一些约定。
对于单个元素:
auto* x = new int; // undefined value
auto* x = new int{}; // 0 (default initializer)
auto* x = new int(23); // 23 (copy initializer)
auto* x = new Test; // default constructor
auto* x = new Test{}; // default constructor
auto* x = new Test(...); // X constructor (overload-chosen)
这很有意义,除非您尝试在数组上应用相同的逻辑:
auto* x = new int[10]; // all undefined values - OK
auto* x = new int[10]{}; // all 0 (default initializer) - OK
auto* x = new int[10](23); // all 23 (copy initializer on all) - NOT IMPLEMENTED
auto* x = new Test[10]; // default constructors - OK
auto* x = new Test[10]{}; // default constructors - OK
auto* x = new Test[10](...); // X constructor on all (overload-chosen) - NOT IMPLEMENTED
我的逻辑是你可以做一些假设:
- 如果可以使用
T(Args..)
构造类型,则可以构造数组中的每个元素。没有理由不允许T[N](Args...)
语法。
有谁知道为什么这个功能不存在?允许的话会非常好
new int[10](23); // all 23
new Test[10]("asd", 123); // construct all using Test("asd", 123)
编辑:整个想法是避免默认的初始化/构造函数并直接调用我们需要的那个。
最佳答案
如果标准库中有这方面的东西就好了†,您想要的功能实现起来相对简单:
namespace detail {
template<typename T, typename... ArgTs, std::size_t... Is>
constexpr auto make_filled_array(ArgTs const&... args, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{(Is, T(args...))...}};
}
}
template<typename T, std::size_t N, typename... ArgTs, std::enable_if_t<N != 0, int> = 0>
constexpr auto make_filled_array(ArgTs const&... args) {
return detail::make_filled_array<T, ArgTs...>(args..., std::make_index_sequence<N>{});
}
// ...
auto arr1 = make_filled_array<int, 10>(23);
auto arr2 = make_filled_array<Test, 10>("asd", 123);
就是说,我认为在这里使用构造函数参数没有任何意义;容器emplace
函数很有用,因为它们可以进行完美转发,但我们不能在这里这样做,因为我们需要为每个构造函数调用重用参数(因此从它们转移不是一种选择)。我认为复制构造是自然的:
namespace detail {
template<typename T, std::size_t... Is>
constexpr auto make_filled_array(T const& t, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{(Is, t)...}};
}
}
template<std::size_t N, typename T, std::enable_if_t<N != 0, int> = 0>
constexpr auto make_filled_array(T const& t) {
return detail::make_filled_array(t, std::make_index_sequence<N>{});
}
// ...
auto arr1 = make_filled_array<10>(23);
auto arr2 = make_filled_array<10>(Test{"asd", 123});
注意您对 new
的使用暗示您可能来自托管语言并且需要阅读值语义。 ;-] 此代码可以 更改为返回 std::array<T, N>*
或 T*
(甚至是 std::unique_ptr<T[]>
适度合理的东西),但是,为什么会有一个..?只需使用 std::vector<T>
:
std::vector<int> vec(10, 23);
我选择演示std::array<>
在这里是因为您的示例都具有恒定大小。
† 想到的最接近的是 std::fill
,但这不会初始化数组...
关于c++ - 允许为所有数组元素调用任何构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48610895/