可变参数模板到数组访问的无递归扩展

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, ...);

【讨论】:

以上是关于可变参数模板到数组访问的无递归扩展的主要内容,如果未能解决你的问题,请参考以下文章

在可变参数模板类中初始化静态数组

如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?

是否可以 NATVIS 递归元组(可变参数模板)?

可变参数模板包扩展

第21课 可变参数模板_展开参数包

C++11 ——— 可变参数模板