可变参数模板到数组访问的无递归扩展
Posted
技术标签:
【中文标题】可变参数模板到数组访问的无递归扩展【英文标题】:Recursion-free expansion of variadic template into array access 【发布时间】:2021-02-18 06:02:24 【问题描述】:考虑以下非类型可变参数模板函数:
template <typename dummy = void>
void write_at_offsets(volatile char *p)
template <size_t OFF, size_t... OFFs>
void write_at_offsets(volatile char *p)
p[OFF] = 1;
write_at_offsets<OFFs...>(p);
它使用递归的方法在模板参数包中指定的偏移处写入1。
这是否可以在不使用 C++11 中的递归的情况下简洁地编写,例如一次性扩展整个包?
【问题讨论】:
【参考方案1】:您可以使用 fold 表达式(c++17 起),在index_sequence
中传递偏移量:
template<size_t ... Indices>
void foo(std::index_sequence<Indices...>,volatile char* p)
( (p[Indices] = 1),... );
int main()
char* p = new char[3];
foo(std::index_sequence<0,1,2>(),p);
使用 C++11 创建的假数组使用逗号表达式 (Calculation,0)
填充为 0:
template<size_t ... Indices>
void foo(char* p, const int val)
int fake[] = (p[Indices] = val,0)... ;
// cast fake to void to prevent compiler warning present
int main()
char* p = new char[3];
foo<0,1,2>(p,48);
【讨论】:
如果没有std::index_sequence
也行不通吗? (我的意思是 - 更接近 OP 代码。)我摆弄了你的例子:Demo on coliru
@Scheff Nice version :),你说得对,在我的示例中 index_sequence 在某种程度上是多余的。
是的,这是我在 C++17 中使用的,但这里我仅限于 C++11。
@BeeOnRope 添加了 C++11 版本。【参考方案2】:
是的,可以只使用 C++11 结构。
template <size_t... OFFs>
void write_at_offsets(volatile char *p)
dummyfunc((p[OFFs] = 1, 0) ...) ;
dummyfunc
是任何忽略其参数的旧可变参数函数。
不直接传递赋值结果,因为现在不推荐将赋值结果用于 volatile 变量(尽管它不在 C++11 中)。
【讨论】:
注意,然后未指定评估顺序,并且从左到右。 @Jarod42 你是对的,这可能是个问题。【参考方案3】:在这种简单的情况下,您可以使用常规循环:
template <std::size_t... OFFs>
void write_at_offsets(volatile char *p)
for (std::size_t i : OFFs)
p[i] = 1;
C++11/C++14还有一些技巧可以模拟C++17的一些折叠表达式:
template <std::size_t... OFFs>
void write_at_offsets(volatile char *p)
const int dummy[] = 0, (p[OFFs] = 1, 0)...;
static_cast<void>(dummy); // Avoid warning for unused variable
而 C++17 只是
template <std::size_t... OFFs>
void write_at_offsets(volatile char *p)
(p[OFFs] = 1, ...);
【讨论】:
以上是关于可变参数模板到数组访问的无递归扩展的主要内容,如果未能解决你的问题,请参考以下文章