使用 std::index_sequence 初始化具有固定大小数组成员的 POD 结构容器
using std::index_sequence to initialize POD struct container with fixed size array members
我正在尝试使用 std::integer_sequence
and its helper template std::index_sequence
来初始化一个固定大小的 POD 结构,其行为类似于容器。每个元素依次包含一个固定大小的数组字段。
容器 POD 结构本质上定义为:
#define ELEM_NAME_SIZE 7
#define CONTAINER_SIZE 20
using Container = struct Container {
int entries;
Element elems[MAX_CONTAINER_SIZE];
};
单个元素是:
using Element = struct Element {
char name[MAX_NAME_CHARS];
bool bFlag;
};
基于 的答案,我能够使用 std::index_sequence
初始化固定长度 Element
s。到目前为止一切顺利。
我需要想出一种方法来构造 Container
具有单个固定大小 const char*
- 比如“ABCDEF”,或者使用固定长度的数组(最多最多 ELEM_NAME_SIZE) 个字符串。
constexpr char gTestNames[3][ELEM_NAME_SIZE] = {
"APPLE", "BEE", "CHAIN"
};
在live coliru code中,第一个容器构造函数如下:
template<std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(char const (&name)[N]) {
return makeContainer_in(name, Indices{});
}
正在构建并打印出容器的内容,产量为:
const auto container = makeContainer("ABCDEF");
std::cout << container << '\n';
输出:
Container: entries(7)[Element:[ABCDEF],,Element:[],,Element:[],,Element:[],,Element:[],,Element:[],,Element:[],,]
但是,使用替代模板函数重载,参数为 gTestNames
:
template<std::size_t N, std::size_t NAME_LEN_MAX = ELEM_NAME_SIZE, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(const char(&names)[N][NAME_LEN_MAX]) {
return makeContainer_in(names, Indices{});
}
调用使用:
const auto container1 = makeContainer(gTestNames);
std::cout << container1 << '\n';;
我得到以下错误输出:
main.cpp: In instantiation of 'constexpr Container makeContainer(const char (&)[N][NAME_LEN_MAX]) [with long unsigned int N = 3; long unsigned int NAME_LEN_MAX = 7; Indices = std::integer_sequence<long unsigned int, 0, 1, 2>; Container = Container]':
main.cpp:78:53: required from here
main.cpp:64:28: error: no matching function for call to 'makeContainer_in(const char [3][7], std::integer_sequence<long unsigned int, 0, 1, 2>)'
64 | return makeContainer_in(names, Indices{});
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
main.cpp:52:21: note: candidate: 'template<long unsigned int N, long unsigned int ...Is> constexpr Container makeContainer_in(const char (&)[N], std::index_sequence<Is ...>)'
52 | constexpr Container makeContainer_in(char const (&packed)[N], std::index_sequence<Is...>) {
| ^~~~~~~~~~~~~~~~
main.cpp:52:21: note: template argument deduction/substitution failed:
main.cpp:64:28: note: mismatched types 'const char' and 'const char [7]'
64 | return makeContainer_in(names, Indices{});
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
如果可能的话,除了纠正我的错误之外,有没有什么方法可以简化所有这些样板代码——也许使用折叠表达式——我想使用 index_sequences(因为我正在努力学习如何使用它们),但我从来不理解总是将调用转发给某种代理以扩展索引的要求。一定有更简单的方法。
当然可以:
template<std::size_t N, std::size_t... Is>
constexpr Container makeContainer_in(char const (&packed)[N], std::index_sequence<Is...>) {
return Container{ N, { packed[Is]... } };
}
不会工作,Container
有一个 Element
,而不是 char
(并且 Element
没有 Element::Element(char)
构造函数)。只需在参数包内使用它的构造函数实例化实际的容器元素。
template<std::size_t N, std::size_t... Is>
constexpr Element makeElement_in(char const (&name)[N], std::index_sequence<Is...>) {
return Element{ { name[Is]... }, true, };
}
template<std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr Element makeElement(char const (&name)[N]) {
return makeElement_in(name, Indices{});
}
template<std::size_t N, std::size_t NAME_LEN_MAX, std::size_t... Is>
constexpr Container makeContainer_in(const char(&names)[N][NAME_LEN_MAX], std::index_sequence<Is...>) {
return Container{ N, { makeElement(names[Is])... } };
}
template<std::size_t N, std::size_t NAME_LEN_MAX, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(const char(&names)[N][NAME_LEN_MAX]) {
return makeContainer_in(names, Indices{});
}
如果您希望输出遵循给定的输出 HELLO
Element:[H], Element:[E], Element:[L], Element:[L], Element:[O],
此代码可以工作,但如果您传递以空字符结尾的字符串,将会有一个空字符元素。
#include <iostream>
#include <tuple>
#define MAX_NAME_CHARS 9
#define MAX_CONTAINER_SIZE 100
struct Element {
char name[MAX_NAME_CHARS];
bool bFlag;
int foo;
friend std::ostream& operator << (std::ostream& os, const Element& next) {
os << next.name;
return os;
}
};
struct Container {
int entries;
Element elems[MAX_CONTAINER_SIZE];
friend std::ostream& operator << (std::ostream& os, const Container& next) {
os << "Container: entries(" << next.entries << ")[";
for (auto i = 0; i<next.entries; ++i) {
os << next.elems[i] << ",";
}
os << "]\n";
return os;
}
};
template<std::size_t N, std::size_t ... I>
constexpr Container makeContainerInSingle(const char(&singlecharnames)[N],
std::index_sequence<I...>) {
auto result = Container {
N,
{Element{
{singlecharnames[I]},
true,
0}...
}
};
return result;
}
template<std::size_t N>
constexpr Container makeContainerSingle(const char(&singlecharnames)[N]) {
return makeContainerInSingle(singlecharnames, std::make_index_sequence<N>{});
}
int main() {
auto c2 = makeContainerSingle("HELLO");
std::cout << c2 << std::endl;
}
输出如下
Container: entries(6)[H,E,L,L,O,,]
作为附加说明,我不确定使用 std::index_sequence
可以做些什么来简化模式,尽管如果您认为索引序列更简单,可以像我的示例代码一样直接构建索引序列.
我正在尝试使用 std::integer_sequence
and its helper template std::index_sequence
来初始化一个固定大小的 POD 结构,其行为类似于容器。每个元素依次包含一个固定大小的数组字段。
容器 POD 结构本质上定义为:
#define ELEM_NAME_SIZE 7
#define CONTAINER_SIZE 20
using Container = struct Container {
int entries;
Element elems[MAX_CONTAINER_SIZE];
};
单个元素是:
using Element = struct Element {
char name[MAX_NAME_CHARS];
bool bFlag;
};
基于 std::index_sequence
初始化固定长度 Element
s。到目前为止一切顺利。
我需要想出一种方法来构造 Container
具有单个固定大小 const char*
- 比如“ABCDEF”,或者使用固定长度的数组(最多最多 ELEM_NAME_SIZE) 个字符串。
constexpr char gTestNames[3][ELEM_NAME_SIZE] = {
"APPLE", "BEE", "CHAIN"
};
在live coliru code中,第一个容器构造函数如下:
template<std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(char const (&name)[N]) {
return makeContainer_in(name, Indices{});
}
正在构建并打印出容器的内容,产量为:
const auto container = makeContainer("ABCDEF");
std::cout << container << '\n';
输出:
Container: entries(7)[Element:[ABCDEF],,Element:[],,Element:[],,Element:[],,Element:[],,Element:[],,Element:[],,]
但是,使用替代模板函数重载,参数为 gTestNames
:
template<std::size_t N, std::size_t NAME_LEN_MAX = ELEM_NAME_SIZE, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(const char(&names)[N][NAME_LEN_MAX]) {
return makeContainer_in(names, Indices{});
}
调用使用:
const auto container1 = makeContainer(gTestNames);
std::cout << container1 << '\n';;
我得到以下错误输出:
main.cpp: In instantiation of 'constexpr Container makeContainer(const char (&)[N][NAME_LEN_MAX]) [with long unsigned int N = 3; long unsigned int NAME_LEN_MAX = 7; Indices = std::integer_sequence<long unsigned int, 0, 1, 2>; Container = Container]':
main.cpp:78:53: required from here
main.cpp:64:28: error: no matching function for call to 'makeContainer_in(const char [3][7], std::integer_sequence<long unsigned int, 0, 1, 2>)'
64 | return makeContainer_in(names, Indices{});
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
main.cpp:52:21: note: candidate: 'template<long unsigned int N, long unsigned int ...Is> constexpr Container makeContainer_in(const char (&)[N], std::index_sequence<Is ...>)'
52 | constexpr Container makeContainer_in(char const (&packed)[N], std::index_sequence<Is...>) {
| ^~~~~~~~~~~~~~~~
main.cpp:52:21: note: template argument deduction/substitution failed:
main.cpp:64:28: note: mismatched types 'const char' and 'const char [7]'
64 | return makeContainer_in(names, Indices{});
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
如果可能的话,除了纠正我的错误之外,有没有什么方法可以简化所有这些样板代码——也许使用折叠表达式——我想使用 index_sequences(因为我正在努力学习如何使用它们),但我从来不理解总是将调用转发给某种代理以扩展索引的要求。一定有更简单的方法。
当然可以:
template<std::size_t N, std::size_t... Is>
constexpr Container makeContainer_in(char const (&packed)[N], std::index_sequence<Is...>) {
return Container{ N, { packed[Is]... } };
}
不会工作,Container
有一个 Element
,而不是 char
(并且 Element
没有 Element::Element(char)
构造函数)。只需在参数包内使用它的构造函数实例化实际的容器元素。
template<std::size_t N, std::size_t... Is>
constexpr Element makeElement_in(char const (&name)[N], std::index_sequence<Is...>) {
return Element{ { name[Is]... }, true, };
}
template<std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr Element makeElement(char const (&name)[N]) {
return makeElement_in(name, Indices{});
}
template<std::size_t N, std::size_t NAME_LEN_MAX, std::size_t... Is>
constexpr Container makeContainer_in(const char(&names)[N][NAME_LEN_MAX], std::index_sequence<Is...>) {
return Container{ N, { makeElement(names[Is])... } };
}
template<std::size_t N, std::size_t NAME_LEN_MAX, typename Indices = std::make_index_sequence<N>>
constexpr Container makeContainer(const char(&names)[N][NAME_LEN_MAX]) {
return makeContainer_in(names, Indices{});
}
如果您希望输出遵循给定的输出 HELLO
Element:[H], Element:[E], Element:[L], Element:[L], Element:[O],
此代码可以工作,但如果您传递以空字符结尾的字符串,将会有一个空字符元素。
#include <iostream>
#include <tuple>
#define MAX_NAME_CHARS 9
#define MAX_CONTAINER_SIZE 100
struct Element {
char name[MAX_NAME_CHARS];
bool bFlag;
int foo;
friend std::ostream& operator << (std::ostream& os, const Element& next) {
os << next.name;
return os;
}
};
struct Container {
int entries;
Element elems[MAX_CONTAINER_SIZE];
friend std::ostream& operator << (std::ostream& os, const Container& next) {
os << "Container: entries(" << next.entries << ")[";
for (auto i = 0; i<next.entries; ++i) {
os << next.elems[i] << ",";
}
os << "]\n";
return os;
}
};
template<std::size_t N, std::size_t ... I>
constexpr Container makeContainerInSingle(const char(&singlecharnames)[N],
std::index_sequence<I...>) {
auto result = Container {
N,
{Element{
{singlecharnames[I]},
true,
0}...
}
};
return result;
}
template<std::size_t N>
constexpr Container makeContainerSingle(const char(&singlecharnames)[N]) {
return makeContainerInSingle(singlecharnames, std::make_index_sequence<N>{});
}
int main() {
auto c2 = makeContainerSingle("HELLO");
std::cout << c2 << std::endl;
}
输出如下
Container: entries(6)[H,E,L,L,O,,]
作为附加说明,我不确定使用 std::index_sequence
可以做些什么来简化模式,尽管如果您认为索引序列更简单,可以像我的示例代码一样直接构建索引序列.