Recursion-free expansion of variadic template into array access

Viewed 133

Consider the follow non-type variadic template function:

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);
}

It uses the recursive approach to write a 1 at the offsets specified in the template parameter pack.

Can this be written succinctly without using recursion in C++11, e.g., by expanding the whole pack in one shot?

3 Answers

You can use fold expressions (since c++17), passing offsets in 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);

With C++11 created fake array filled by 0 with using comma expression (Calculation,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);

Yes it is possible using only C++11 constructs.

template <size_t... OFFs>
void write_at_offsets(volatile char *p) {
    dummyfunc((p[OFFs] = 1, 0) ...) ;  
}

dummyfunc is any old variadic function that ignores its arguments.

Not passing the result of assignment directly because using the result of assignment to a volatile variable is now deprecated (though it wasn't in C++11).

In simple case like this, you might use regular loop:

template <std::size_t... OFFs>
void write_at_offsets(volatile char *p) {
    for (std::size_t i : {OFFs}) {
        p[i] = 1;
    }
}

Else there are tricks in C++11/C++14 to simulate some fold expression of 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
}

whereas C++17 would simply be

template <std::size_t... OFFs>
void write_at_offsets(volatile char *p) {
    (p[OFFs] = 1, ...);
}
Related