dar*_*une 8 c++ initializer-list constexpr c++17
假设我有一些假设的结构:
struct X {
int i;
double d;
}
Run Code Online (Sandbox Code Playgroud)
然后我可以写
constexpr X x_c_array[]{{5, 6.3}};
Run Code Online (Sandbox Code Playgroud)
要么
constexpr std::initializer_list<X> x_ilist{{5, 6.3}};
Run Code Online (Sandbox Code Playgroud)
auto不可能使用-编译器必须知道内部类型。
这两个版本都有缺点吗?
更新:
同样值得关注的是,您是否能够使用/将一种类型转换为另一种类型-例如。在构造标准容器时?
简单明了:initializer_list不是容器。这是外部分配元素的不变视图。完全不适合容器将在其中使用的任何情况-考虑不必要的间接(无可调整性),不变性,其名称的惯用语。最重要的是,它没有适当的接口。
似乎都合适的情况是序列的构造函数参数。如果长度是固定的(或模板参数化),则int const (&arr)[N]可以,尽管initializer_list它更简单,更灵活。毕竟,这就是它的设计意图。
正如评论中所写,这是一个广泛的论点。
无论如何,我提请您注意一点。
第一种情况
X x1[] {{5, 6.3}};
Run Code Online (Sandbox Code Playgroud)
的元素数量x1是类型的一部分x1。
所以你有那个
X x1[] {{5, 6.3}};
X x2[] {{5, 6.3}, {7, 8.1}};
static_assert( false == std::is_same<decltype(x1), decltype(x2)>::value );
Run Code Online (Sandbox Code Playgroud)
使用初始化列表
std::initializer_list<X> x3 {{5, 6.3}};
std::initializer_list<X> x4 {{5, 6.3}, {7, 8.1}};
static_assert( true == std::is_same<decltype(x3), decltype(x4)>::value );
Run Code Online (Sandbox Code Playgroud)
类型保持不变,改变元素的数量。
根据您的需求,这可能是第一个或第二个解决方案的优势。
事实上,元素的数量是 C 风格数组类型的一部分,这在元编程中可能是一个小小的优势。
假设您想要一个返回i数组值之和的函数,您可以使用 C 风格数组编写
template <std::size_t N, std::size_t ... Is>
constexpr auto sum_i_helper (X const (&xArr)[N], std::index_sequence<Is...>)
{ return (... + xArr[Is].i); }
template <std::size_t N>
constexpr auto sum_i (X const (&xArr)[N])
{ return sum_i_helper(xArr, std::make_index_sequence<N>{}); }
Run Code Online (Sandbox Code Playgroud)
当 的参数sum_i()是非 constexpr 值时,该函数也会编译。
如果您想编写类似的内容,std::initializer_list则稍微复杂一些,因为size()列表的 不一定是编译时已知值,所以或者您将其作为模板参数传递(但该函数不适用于运行时列表)或者您size()在函数内部使用,但不能使用它来初始化std::index_sequence.
无论如何,使用初始化列表,您可以使用旧的for()循环
constexpr auto sum_i (std::initializer_list<X> const lx)
{
int ret { 0 };
for ( auto const & x : lx )
ret += x.i;
return ret;
}
Run Code Online (Sandbox Code Playgroud)
lx当是一个值时,该函数可以计算编译时间constexpr。
另外值得关注的是,您是否能够使用/将一种类型转换为另一种类型 - 例如。建造标准集装箱时?
将数组转换为初始值设定项列表很容易,并且可以使用编译时和运行时已知值
template <std::size_t N, std::size_t ... Is>
constexpr auto convertX_h (X const (&xArr)[N], std::index_sequence<Is...>)
{ return std::initializer_list<X>{ xArr[Is]... }; }
template <std::size_t N>
constexpr auto convertX (X const (&xArr)[N])
{ return convertX_h(xArr, std::make_index_sequence<N>{}); }
// ....
X x1[] {{5, 6.3}};
std::initializer_list<X> x5 = convertX(x1);
Run Code Online (Sandbox Code Playgroud)
将初始值设定项列表转换为 C 样式数组更加困难,因为数组的类型取决于元素的数量,因此您需要在编译时知道初始值设定项列表中的元素数量,因为您无法随机访问一个初始值设定项列表,更糟糕的是,因为您无法编写返回 C 样式数组的函数。
我可以想象一个如下的解决方案,将初始化列表转换为std::array(题外话建议:std::array如果可能的话,使用 ,而不是 C 样式数组)
template <std::size_t N>
constexpr auto convertX (std::initializer_list<X> const lx)
{
std::array<X, N> ret;
std::size_t i { 0u };
for ( auto const & x : lx )
ret[i++] = x;
return ret;
}
// ...
constexpr std::initializer_list<X> x4 {{5, 6.3}, {7, 8.1}};
auto x6 = convertX<x4.size()>(x4);
Run Code Online (Sandbox Code Playgroud)
但x6now 是 a std::array<X, 2>,而不是 a X[2],并且x4必须是一个constexpr值。