如何使含可变参数列表的嵌套结构体无需预声明子项即可constexpr初始化?
问题描述
现有如下结构体布局:
#include <vector> struct A { char const* name; std::vector<char const*> list; }; struct B { char const* group_name; A an_A; int other_stuff; };
初始化方式如下:
B b = { "My B", { "My A", {{ "My", "variable", "length", "list" }} }, 42 };
需要找到一种定义方式,让b可以被声明为constexpr,且无需在主项之前声明子项。
尝试用std::initializer_list的问题
修改结构体为使用std::initializer_list以支持constexpr:
#include <initializer_list> struct A { char const* name; std::initializer_list<char const*> list; }; struct B { char const* group_name; A an_A; int other_stuff; }; B b = { "My B", { "My A", {{ "My", "variable", "length", "list" }} }, 42 };
但出现编译错误:
<source>:20:1: error: could not convert '{{"My", "variable", "length", "list"}}' from '<brace-enclosed initializer list>' to 'std::initializer_list<const char*>' 20 | }; | ^ | | | <brace-enclosed initializer list> ASM generation compiler returned: 1 <source>:20:1: error: could not convert '{{"My", "variable", "length", "list"}}' from '<brace-enclosed initializer list>' to 'std::initializer_list<const char*>' 20 | }; | ^ | | | <brace-enclosed initializer list> Execution build compiler returned: 1
错误原因是初始化std::initializer_list时多嵌套了一层大括号,std::initializer_list直接接受单层大括号的元素列表即可。
可行解决方案
1. 修正std::initializer_list初始化(C++11及以上)
去掉多余的大括号,即可正常声明constexpr变量:
#include <initializer_list> struct A { char const* name; std::initializer_list<char const*> list; }; struct B { char const* group_name; A an_A; int other_stuff; }; constexpr B b = { "My B", { "My A", { "My", "variable", "length", "list" } }, 42 };
std::initializer_list在constexpr上下文中会指向编译器生成的只读数组,生命周期与b一致,满足需求。
2. 使用C++20 constexpr std::vector
如果需要完整的容器功能而非仅列表视图,C++20开始std::vector支持constexpr初始化,直接修改原始代码即可:
#include <vector> struct A { char const* name; std::vector<char const*> list; }; struct B { char const* group_name; A an_A; int other_stuff; }; constexpr B b = { "My B", { "My A", { "My", "variable", "length", "list" } }, 42 };
注意需要启用C++20或更高版本的编译标准。
3. 自定义constexpr数组容器(兼容C++11/14)
若需兼容更早的C++标准,可自定义轻量级数组结构体实现可变长度constexpr列表:
template <size_t N> struct ConstArray { char const* data[N]; constexpr size_t size() const { return N; } constexpr char const* operator[](size_t idx) const { return data[idx]; } }; struct A { char const* name; ConstArray<0> list; template <size_t N> constexpr A(char const* n, ConstArray<N> arr) : name(n), list(arr) {} }; struct B { char const* group_name; A an_A; int other_stuff; }; constexpr B b = { "My B", { "My A", ConstArray<4>{ "My", "variable", "length", "list" } }, 42 };
这种方式在C++11及以上版本中可正常编译,同时保留可变长度列表的constexpr特性。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

