如何通过元编程生成参数包?

问题描述 投票:0回答:3

假设

template<typename... Types> void bar();

我正在尝试编写一个模板结构 GimmePack 这样

bar< GimmePack<double,3>::type >();

相同
bar< double,double,double >();

问题

这可能吗?

以下是我的尝试。

#include<iostream>

template<typename,size_t,typename...> struct Packstack;

template<typename Tfloat, size_t i, typename ...Types>
    requires(i>0)
struct Packstack<Tfloat,i,Types...>{
    using pack = typename Packstack<Tfloat,i-1,Tfloat,Types...>::pack;
};

template<typename Tfloat, typename ...Types>
struct Packstack<Tfloat,0,Types...>{
    using pack... = Types...;
};

template<typename Tfloat, size_t i>
struct GimmePack{
    using pack = typename Packstack<Tfloat,i>::pack;
};

备注

我知道我可以将 Packstack 元编程代码编织到 bar 的函数定义中。 但在我正在开发的实际源代码中,bar并不是一个简单的函数,而是一个复杂模板类的模板函数,可读性会受到影响。

我还知道,在相同类型的上下文中,信息

double,double,double
相当于信息
double,3
,因此,如果 bar 是结构体,则可以构造
bar
的模板专业化(因为函数的模板专业化无效) c++)。所以我的问题是关于语法而不是概念。

我尝试了什么

在我的实际代码中,我已经尝试重新排列模板的顺序,以便编译器可以找出它们,但我的签名是

template<typename other1, typename other2, typename ...Values> bar(Values... values1, other1 o1, Values... values2, other2 o2);

似乎只要 Values... 在签名中出现两次,编译器就会希望将其显式写入。虽然看起来向量是一个不错的选择,但每个 value1...、values2... 中的数据元素都来自不相关的上下文。

我尝试在 using 语句周围的不同位置放置三个点。

c++ c++20 variadic-templates parameter-pack
3个回答
2
投票

在通用 lambda 表达式上使用显式模板参数列表怎么样?

template <class...>
struct mp_list {};

template <class T, std::size_t I, class... Ts>
auto GimmePack(auto f) {
  if constexpr (I == 0) {
    return f(mp_list<Ts...>{});
  } else {
    return GimmePack<T, I - 1, T, Ts...>(f);
  }
}

...

// same as bar<double, double, double>();
GimmePack<double, 3>([]<class... Ts>(mp_list<Ts...>) {
  return bar<Ts...>();
});

在 Godbolt 上尝试一下


0
投票

您可以使用变量模板。

#include <tuple>

template <typename T, int N>
struct GimmePack{
    //using type = ...;
}

template<typename O1, typename O2, typename... Values> void bar(Values... values1, O1 other1, Values... values2, O2 other){
    //...
}

template<typename O1, typename O2, typename T>
void (*make_bar)() = nullptr;

template<typename O1, typename O2, typename... Ts>
void (*make_bar<O1, O2, std::tuple<Ts...>>)(Ts..., O1, Ts..., O2) = bar<O1, O2, Ts...>;

template <typename... Args>
void caller(Args... args){
   make_bar<int, int, std::tuple<double, double>>(args...); // equivalent to bar<int, int, double, double>(args...);
   make_bar<int, int, GimmePack<double, 2>::type>(args...); // same
}

-2
投票

这只是一个想法:

你尝试过模板特化和递归吗?

// The type is (T) and count is (N).
template<typename T, int N>
struct MyStruct {
    using type = typename MyStruct<T, N - 1>::type;
};

template<typename T>
struct MyStruct<T, 0> {
    using type = T;
};

现在我们使用

MyStruct
bar
函数生成所需的参数包:

template<typename... Types>
void bar();

using MyPack = typename MyStruct<double, 3>::type;
bar<MyPack>();
© www.soinside.com 2019 - 2024. All rights reserved.