C++ 基于模板参数的另一个包创建参数包
假设有几个模板类(结构),它们的对象构成了序列-让我们称它们为N_mod(N-特定类的说明符),以及定义序列中第一个元素的特殊类-first_mod。除第一个模块外,每个类都有自己的“接口生成器”-N\u生成器---模板类:C++ 基于模板参数的另一个包创建参数包,c++,templates,c++11,metaprogramming,variadic-templates,C++,Templates,C++11,Metaprogramming,Variadic Templates,假设有几个模板类(结构),它们的对象构成了序列-让我们称它们为N_mod(N-特定类的说明符),以及定义序列中第一个元素的特殊类-first_mod。除第一个模块外,每个类都有自己的“接口生成器”-N\u生成器---模板类: template<int targ> struct First_mod //First element in sequence - without appropriate builder interface { }; //Let's consider tw
template<int targ>
struct First_mod //First element in sequence - without appropriate builder interface
{ };
//Let's consider two types of N_mod - A_mod and B_mod
template<int targ, int param>
struct A_mod
{ };
template<int param>
struct A_builder//Builder for A_mod objects
{ };
template<int targ, int param>
struct B_mod
{ };
template<int param>
struct B_builder//Builder for B_mod objects
{ };
模板
struct First_mod//序列中的第一个元素-没有适当的生成器界面
{ };
/让我们考虑两种类型的NU-MOD-AYMOD和BMODD。
样板
结构A_mod
{ };
样板
struct A_builder//A_mod objects的builder
{ };
样板
结构B_mod
{ };
样板
结构B_生成器//B_mod对象的生成器
{ };
现在,我需要根据以下简单规则,从适当的N\u构建器的现有序列中生成First\u mod和N\u mod对象序列:
如果N_Mod(i)等于A_Mod则targ(i)=参数(i)-targ(i-1)
else(即N_Mod(i)等于B_Mod)target(i)=参数(i)*target(i-1)
为了清晰起见,我的草图:
template<typename...builders>
struct mod_seq_gen
{
typedef /*generated First_mod, A_mod and B_mod sequence pack. How to do it?*/ modseq;
};
template<typename...builders>
struct Container
{
std::tuple</*here must be mod-sequence generator that creates
mod parameters pack and unpacks them:*/
mod_seq_gen<builders...>::modseq
> mod_sequence;
};
int main()
{
/*In this case must be generated next sequence and stored in
* mod_sequence tuple:
* First_mod<3> - A_mod<5-3, 5> - B_mod<2*(5-3), 2>
*/
Container<First_mod<3>, A_builder<5>, B_builder<2>> obj;
}
模板
结构模块顺序生成
{
typedef/*生成第一个\模、A \模和B \模序列包。如何执行?*/modseq;
};
样板
结构容器
{
std::tuple mod_序列;
};
int main()
{
/*在这种情况下,必须生成下一个序列并存储在
*mod_序列元组:
*第一个模式-A模式-B模式
*/
集装箱obj;
}
我请求帮助您实施mod_seq_gen,或者为整个任务提供一些其他提示 首先,我将转储(编译)解决方案:
#include <tuple>
#include <utility>
#include <iostream>
template<int targ>
struct First_mod //First element in sequence - without appropriate builder interface
{ void print() { std::cout << "First_mod["<<targ<<"]" << std::endl; } };
//Let's consider two types of N_mod - A_mod and B_mod
template<int targ, int param>
struct A_mod
{ void print() { std::cout << "A_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct A_builder//Builder for A_mod objects
{
// publish the template parameter (not necessary)
static const int param_value = param;
// provide a way to compute the current targ
static constexpr int calc_targ(int prev_targ)
{
return param - prev_targ;
}
// provide a way to build the type
template < int targ >
using type = A_mod<targ, param>;
};
template<int targ, int param>
struct B_mod
{ void print() { std::cout << "B_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct B_builder//Builder for B_mod objects
{
static const int param_value = param;
static constexpr int calc_targ(int prev_targ)
{
return prev_targ * param;
}
template < int targ >
using type = B_mod<targ, param>;
};
// just a helper, wonder if there's something in the Standard Library o.O
template < typename... Tuples >
using tuple_cat_types = decltype(tuple_cat( std::declval<Tuples>()... ));
// the generator of the tuple
template < typename TFirst_mod, typename... TBuilders >
struct gen;
// restrict the first type to a specialization of `First_mod`
// isn't necessary, strictly speaking. We just need the first targ.
// Could as well require a nested `static const int targ = ..;`
template < int first_targ, typename... TBuilders >
struct gen < First_mod<first_targ>, TBuilders... >
{
// recursive helper for the types to be built
// general case for no template arguments in the pack
template < int prev_targ, typename... TBuilders2 >
struct helper { using type = std::tuple<>; };
// specialized case for recursion
// note: the recursion here occurs as a nested typedef, not inheritance
// (simplifies use of calculated targ)
template < int prev_targ, typename TBuilder, typename... TBuilders2 >
struct helper<prev_targ, TBuilder, TBuilders2...>
{
// build type using builder
static const int targ = TBuilder::calc_targ(prev_targ);
using built_type = typename TBuilder::template type<targ>;
// recurse
using further_types = typename helper<targ, TBuilders2...>::type;
// concatenate tuple
using type = tuple_cat_types<std::tuple<built_type>, further_types>;
};
// concatenate tuple with First_mod
using type = tuple_cat_types<std::tuple<First_mod<first_targ>>,
typename helper<first_targ, TBuilders...>::type>;
};
int main()
{
gen<First_mod<3>, A_builder<5>, B_builder<2>>::type x;
static_assert(std::tuple_size<decltype(x)>::value == 3, "!");
std::get<0>(x).print();
std::get<1>(x).print();
std::get<2>(x).print();
}
首先,我将转储(编译)解决方案:
#include <tuple>
#include <utility>
#include <iostream>
template<int targ>
struct First_mod //First element in sequence - without appropriate builder interface
{ void print() { std::cout << "First_mod["<<targ<<"]" << std::endl; } };
//Let's consider two types of N_mod - A_mod and B_mod
template<int targ, int param>
struct A_mod
{ void print() { std::cout << "A_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct A_builder//Builder for A_mod objects
{
// publish the template parameter (not necessary)
static const int param_value = param;
// provide a way to compute the current targ
static constexpr int calc_targ(int prev_targ)
{
return param - prev_targ;
}
// provide a way to build the type
template < int targ >
using type = A_mod<targ, param>;
};
template<int targ, int param>
struct B_mod
{ void print() { std::cout << "B_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct B_builder//Builder for B_mod objects
{
static const int param_value = param;
static constexpr int calc_targ(int prev_targ)
{
return prev_targ * param;
}
template < int targ >
using type = B_mod<targ, param>;
};
// just a helper, wonder if there's something in the Standard Library o.O
template < typename... Tuples >
using tuple_cat_types = decltype(tuple_cat( std::declval<Tuples>()... ));
// the generator of the tuple
template < typename TFirst_mod, typename... TBuilders >
struct gen;
// restrict the first type to a specialization of `First_mod`
// isn't necessary, strictly speaking. We just need the first targ.
// Could as well require a nested `static const int targ = ..;`
template < int first_targ, typename... TBuilders >
struct gen < First_mod<first_targ>, TBuilders... >
{
// recursive helper for the types to be built
// general case for no template arguments in the pack
template < int prev_targ, typename... TBuilders2 >
struct helper { using type = std::tuple<>; };
// specialized case for recursion
// note: the recursion here occurs as a nested typedef, not inheritance
// (simplifies use of calculated targ)
template < int prev_targ, typename TBuilder, typename... TBuilders2 >
struct helper<prev_targ, TBuilder, TBuilders2...>
{
// build type using builder
static const int targ = TBuilder::calc_targ(prev_targ);
using built_type = typename TBuilder::template type<targ>;
// recurse
using further_types = typename helper<targ, TBuilders2...>::type;
// concatenate tuple
using type = tuple_cat_types<std::tuple<built_type>, further_types>;
};
// concatenate tuple with First_mod
using type = tuple_cat_types<std::tuple<First_mod<first_targ>>,
typename helper<first_targ, TBuilders...>::type>;
};
int main()
{
gen<First_mod<3>, A_builder<5>, B_builder<2>>::type x;
static_assert(std::tuple_size<decltype(x)>::value == 3, "!");
std::get<0>(x).print();
std::get<1>(x).print();
std::get<2>(x).print();
}
您的公式、示例或N_mod的模板参数顺序错误。如果A_mod
A_mod
表示targ(1)=2,param(1)=5,那么A_mod的公式必须是targ(i)=param(i)-targ(i-1)。@DyP,是的,我错了。修正了。在写了东西并得到错误的输出后,我很担心;)(通常,如果这些东西是编译的,那么它们是正确的)我想如果第一种类型也有一个构建器(即使它什么都没有做),可能会简单一些。您可以去掉递归中的“特例”(专门化gen
和元组的第二个连接类型定义)。请参阅使用First\u builder
版本的“编辑我的答案”。您的公式、示例或N\u mod的模板参数顺序都是错误的。如果A_modA_mod
表示targ(1)=2,param(1)=5,那么A_mod的公式必须是targ(i)=param(i)-targ(i-1)。@DyP,是的,我错了。修正了。在写了东西并得到错误的输出后,我很担心;)(通常,如果这些东西是编译的,那么它们是正确的)我想如果第一种类型也有一个构建器(即使它什么都没有做),可能会简单一些。您可以去掉递归中的“特例”(专门化gen
和元组的第二个连接类型定义)。请参阅对我的答案的编辑,以获得使用First\u builder
的版本(我仍在评论/提供一些文档)。@gorill通常,您使用递归来处理此类事情。这里的具体技巧是:1)使构建器尽可能有用2)不要通过继承而递归,而是通过嵌套的typedef(能够使用静态成员和嵌套的typedef)3)连接元组(我仍在评论/提供一些文档。)@gorill通常,这类事情使用递归。这里的具体技巧是:1)使生成器尽可能有用2)不要通过继承递归,而是通过嵌套的typedef(能够使用静态成员和嵌套的typedef)3)连接元组