从模板实参中解包形参包

c++ Unpacking parameter pack from template arguments

本文关键字:形参 包形参 实参      更新时间:2023-10-16

如何实现我想要的?我要解包的形参包不在函数实参列表中,而是在模板实参列表中。

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

我必须使用这种形式的func(而不是func(1,3,7))来让我的大程序工作(我正在处理多个继承问题)。

递归模板解:

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

编辑:受iavr解决方案启发的超级简化版本:

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

这里有一个更简单的解决方案,不需要额外的东西,只是:

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

假设数组先初始化,然后填充。我以前的解决方案在编译时计算所有的值,并用它们直接初始化数组。因此,这可能是更快的编译和较慢的运行。

从c++ 17开始,可以使用折叠表达式:

template <std::size_t... ARGS>
constexpr std::array<bool, SIZE> func() {
    std::array<bool, SIZE> b{};
    ((b[ARGS] = true), ...);    // fold expression
    return b;
}

演示

对于c++ 11和c++ 14,我更喜欢使用一个未命名的lambda,像这样:

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

参见实例

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

其中sizes表示int序列,range <S>构造序列0,...,S-1, in<N, A...>()检查数字N是否在序列A...中(定义见实例)。

这不是最有效的(编译明智的)实现方式,因为对于N...的每个元素,我们都需要扫描A...包。最好并行扫描A...L...包,并修改in()函数。但无论如何,这更容易理解和写下来