c++ Unpacking parameter pack from template arguments

限于喜欢 提交于 2020-05-13 05:44:06

问题


How to achieve want I want below? The paramater pack I want to unpack is not in a function argument list but template argument list.

#include <iostream>
#include <array>

const std::size_t SIZE = 10;

template <int...ARGS>
std::array<bool, SIZE> func() {
    std::array<bool, SIZE> b;
    // I want to set b[n] = true, where n takes on all values from ARGS...
    // what to put in here???
    return b;
}

// Example of what I want to achieve:
int main() {
    const std::array<bool, SIZE> b = func<1,3,7>();
    // I want b[1]==true, b[3]==true, b[7]==true, all others false
    for (int x: b) std::cout << x << std::endl;
}

I have to use this form for func (instead of func(1,3,7)) to get my bigger program working (I'm dealing with multiple inheritance issues).


回答1:


Recursive template solution:

// recursive helper struct
template <int n, int First, int ...Rest>
struct helper {
  static void funcImpl(std::array<bool, SIZE>& temp) {
    temp[First] = true;
    helper<n - 1, Rest...>::funcImpl(temp);
  }
};

// partial specialization to catch base case
template <int First>
struct helper<0, First> {
  static void funcImpl(std::array<bool, SIZE>& temp) {
    temp[First] = true;
  }
};

template <int ...Args>
std::array<bool, SIZE> func() {
    std::array<bool, SIZE> b = {}; // 0 inititalize array
    helper<sizeof...(Args) - 1, Args...>::funcImpl(b);
    return b;
}

EDIT: A super simplified version inspired by iavr's solution:

template <int... A>
std::array<bool, SIZE> func() {
    std::array<bool, SIZE> b = {};
    auto values = {A...};
    std::for_each(values.begin(), values.end(), [&](int n){b[n] = true;});
    return b;
}



回答2:


Here is a much simpler solution that requires nothing extra, just this:

struct _do { template <typename... T> _do(T&&...) { } };

template <int... A>
std::array<bool, SIZE> func() {
    std::array<bool, SIZE> b = {};
    _do{b[A] = true...};
    return b;
}

This assumes the array is first initialized and then populated. My previous solution computed all values at compile time and directly initialized the array with them. So this is probably faster to compile and slower to run.




回答3:


See live example.

Here's the implementation of func:

template <int... A, int... N>
std::array<bool, sizeof...(N)>
func(sizes <N...>)
{
    return std::array<bool, sizeof...(N)>{{in <N, A...>()...}};
}

template <int... A>
std::array<bool, SIZE>
func() { return func <A...>(range <SIZE>()); }

where sizes represents an int sequence, range <S> constructs sequence 0,...,S-1 and in<N, A...>() checks whether number N is in sequence A... (definitions in the live example).

This not the most efficient (compile-wise) way to implement, because for every element of N... we need to scan pack A.... It's better to scan packs A..., L... in parallel, with a modification of function in(). But anyway this was more straightforward to think of and write down.



来源:https://stackoverflow.com/questions/22383372/c-unpacking-parameter-pack-from-template-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!