C++ 在编译时收集模板参数

C++ 在编译时收集模板参数,c++,templates,compile-time,C++,Templates,Compile Time,我有一个类,它将许多其他类作为模板参数(用于编译时语法生成,如果有必要的话),我想知道是否有比手动键入所有内容更好、更可扩展的方法来实现这一点 当前情况: //Class1.h class Class1 {} ... //ClassN.h class ClassN {} //Collection.h struct collectionClass : templateClass<Class1,...,ClassN> //SpecificTemplate.h template<

我有一个类,它将许多其他类作为模板参数(用于编译时语法生成,如果有必要的话),我想知道是否有比手动键入所有内容更好、更可扩展的方法来实现这一点

当前情况:

//Class1.h
class Class1 {}
...
//ClassN.h
class ClassN {}

//Collection.h
struct collectionClass : templateClass<Class1,...,ClassN>

//SpecificTemplate.h
template<> struct specificClass<Class1>{
   //Do the same
}
...
template<> struct specificClass<ClassN>{
   //Do the same
}
//Class1.h
class Class1 {}
REGISTER_CLASS(Class1)
...
//ClassN.h
class ClassN {}
REGISTER_CLASS(ClassN)

//Collection.h
struct collectionClass : templateClass<REGISTERED_CLASSES>

//SpecificTemplate.h
CREATE_CLASSES_FROM_REGISTERED()
//Class1.h
类Class1{}
...
//h类
类ClassN{}
//收藏
结构集合类:模板类
//具体模板.h
模板结构specificClass{
//照做
}
...
模板结构specificClass{
//照做
}
目前,这必须手动完成(对于不同的“收集”类,需要在多个位置进行)

有没有办法将其转变为更好管理的替代方案,如:

所需情况:

//Class1.h
class Class1 {}
...
//ClassN.h
class ClassN {}

//Collection.h
struct collectionClass : templateClass<Class1,...,ClassN>

//SpecificTemplate.h
template<> struct specificClass<Class1>{
   //Do the same
}
...
template<> struct specificClass<ClassN>{
   //Do the same
}
//Class1.h
class Class1 {}
REGISTER_CLASS(Class1)
...
//ClassN.h
class ClassN {}
REGISTER_CLASS(ClassN)

//Collection.h
struct collectionClass : templateClass<REGISTERED_CLASSES>

//SpecificTemplate.h
CREATE_CLASSES_FROM_REGISTERED()
//Class1.h
类Class1{}
注册班(1班)
...
//h类
类ClassN{}
注册类别(类别N)
//收藏
结构集合类:模板类
//具体模板.h
从注册的创建类
在过去的几天里,我一直试图通过BoostPP和MPL实现这一点,但我不确定这是否可行

编辑:

//Class1.h
class Class1 {}
...
//ClassN.h
class ClassN {}

//Collection.h
struct collectionClass : templateClass<Class1,...,ClassN>

//SpecificTemplate.h
template<> struct specificClass<Class1>{
   //Do the same
}
...
template<> struct specificClass<ClassN>{
   //Do the same
}
//Class1.h
class Class1 {}
REGISTER_CLASS(Class1)
...
//ClassN.h
class ClassN {}
REGISTER_CLASS(ClassN)

//Collection.h
struct collectionClass : templateClass<REGISTERED_CLASSES>

//SpecificTemplate.h
CREATE_CLASSES_FROM_REGISTERED()
pegtl需要以下特定实例: 有一些操作预定义为:

template<typename Rule>
struct Action : tao::pegtl::nothing<Rule> {
};
模板
结构操作:tao::pegtl::nothing{
};
并且必须实例化为:

template<>
struct Action<specificRule> {
  static void apply0(State &state) {
    state.rule = specificRule::ID;
  }
};
模板
结构动作{
静态无效应用程序0(状态和状态){
state.rule=specificRule::ID;
}
};
规则的注册 我建议在代码库的单个位置明确手动注册所有“规则”(
Class1
,…,
ClassN
):

// foo_rule.hpp
#pragma once
struct FooRule {};

// bar_rule.hpp
#pragma once
struct BarRule {};

// foobar_rule.hpp
#pragma once
struct FoobarRule {};

// registered_rules.hpp
#pragma once
#include <tuple>
#include "foo_rule.hpp"
#include "bar_rule.hpp"
#include "foobar_rule.hpp"
using RegisteredRules = std::tuple<FooRule, BarRule, FoobarRule>;
让我们为此使用一个名为rewrap的原语。生成上述继承的代码将读取

struct FirstCollection : rewrap<RegisteredRules, TemplateClass> {};
struct SecondCollection : rewrap<RegisteredRules, TemplateClass> {};
专门化注册规则的
操作
在您的问题中,您询问如何专门化所有已注册规则的模板类
操作

template<>
struct Action<FooRule>{
  static void apply0(State& state) {
    // do the same
  }
}
/*...*/
template<>
struct Action<FoobarRule>{
  static void apply0(State& state) {
    // do the same
  }
}
第二个模板参数可用于玩常见的SFINAE游戏:

template<
  class SpecificRule
> struct Action<
  SpecificRule,
  std::enable_if_t<
    is_wrapped_in<SpecificRule, RegisteredRules>// to be implemented
  >
> {
  static void apply0(State&) {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
};
GCC 8.2.0的输出:

static void Nothing<Rule>::apply0(State&) [with Rule = UnregisteredRule]
static void Action<SpecificRule, typename std::enable_if<is_wrapped_in<SpecificRule, std::tuple<FooRule, BarRule, FoobarRule> >, void>::type>::apply0(State&) [with SpecificRule = FooRule]
static void Action<SpecificRule, typename std::enable_if<is_wrapped_in<SpecificRule, std::tuple<FooRule, BarRule, FoobarRule> >, void>::type>::apply0(State&) [with SpecificRule = BarRule]
static void Action<SpecificRule, typename std::enable_if<is_wrapped_in<SpecificRule, std::tuple<FooRule, BarRule, FoobarRule> >, void>::type>::apply0(State&) [with SpecificRule = FoobarRule]
static void Nothing::apply0(State&)[带规则=未注册规则]
静态void操作::apply0(State&)[with SpecificRule=FooRule]
静态无效操作::apply0(State&)[使用SpecificRule=BarRule]
静态无效操作::apply0(State&)[使用SpecificRule=FoobarRule]

我不知道您可以更改多少代码,但是。。。如果您可以计算类
Class1
Class2
ClassN
使它们专门化模板类
ClassX

// class_base.h (additional header)
template <std::size_t>
struct ClassX;
您可以使用类帮助器,
std::index_sequence
std::make_index_sequence
(从C++14开始提供)


在执行上述重载时,可以使用函数重载的巧妙技巧以及派生类型比其基类型具有更高优先级的事实

这将使您能够编写:

TYPE_COLLECTOR_START(foo);

TYPE_COLLECTOR_ADD(foo, int);
TYPE_COLLECTOR_ADD(foo, std::pair<bool, bool>);
TYPE_COLLECTOR_ADD(foo, char);

TYPE_COLLECTOR_END(foo);

static_assert(
    std::is_same_v<foo, type_collector::list<int, std::pair<bool, bool>, char>>
);
然后使用
\uuuu COUNTER\uuuu
定义一个函数重载列表,并增加
版本号:

// the result is stored in this type
template <class... Ts>
struct list {
    template <class T>
    using add = list<Ts..., T>;
};

// macro TYPE_COLLECTOR_START usage will expand to
auto get(version<0>) -> list<>;

// macro TYPE_COLLECTOR_ADD usages will expand to
auto get(version<1>) -> decltype(get(version<0>{}))::add<int>;
auto get(version<2>) -> decltype(get(version<1>{}))::add<std::pair<bool, bool>>;
auto get(version<3>) -> decltype(get(version<2>{}))::add<char>;

// macro TYPE_COLLECTOR_END usage will expand to
using foo = decltype(get(version<3>{}));
//结果存储在此类型中
模板
结构列表{
模板
使用add=list;
};
//宏类型\u收集器\u开始使用将扩展为
自动获取(版本)->列表;
//宏类型\u收集器\u添加用法将扩展为
自动获取(版本)->decltype(获取(版本{}))::添加;
自动获取(版本)->decltype(获取(版本{}))::添加;
自动获取(版本)->decltype(获取(版本{}))::添加;
//宏类型\u收集器\u最终用途将扩展为
使用foo=decltype(get(version{}));
显然,您希望避免名称冲突(并可能同时将类型收集到两个不同的列表中;交叉),因此我编写了一个更全面的示例以供参考

  • 住在
编辑 对于您的特定用例,如果我理解正确,您可以在我上面提供的基础上定义包装宏,它既可以将类型添加到列表中,也可以定义专门化:

#define REGISTER_RULE(rule)\
    TYPE_COLLECTOR_ADD(registered_rules, rule)\
    \
    template <>\
    struct Action<rule_name> {\
        static void apply0(State& state) {\
            state.rule = rule_name::ID;\
        }\
    }
#定义寄存器规则(规则)\
类型\u收集器\u添加(已注册的\u规则,规则)\
\
模板\
结构动作{\
静态无效应用程序0(状态和状态){\
state.rule=规则名称::ID\
}\
}
然后你会有这样的东西:

// registered_rules.h
namespace tao_pegtl_namespace { TYPE_COLLECTOR_START(registered_rules); }

// rule1.h
#include "registered_rules.h"
namespace your_namespace { class rule1 {}; }
namespace tao_pegtl_namespace { REGISTER_RULE(your_namespace::rule1); }

// rule2.h
#include "registered_rules.h"
namespace your_namespace { class rule2 {}; }
namespace tao_pegtl_namespace { REGISTER_RULE(your_namespace::rule2); }

// rules_collection.h
namespace tao_pegtl_namespace {
    TYPE_COLLECTOR_END(registered_rules);
    struct rules_collection : templateClass<(unpack `registered_rules`...)> {}
}
//已注册的\u规则.h
名称空间tao_pegtl_名称空间{TYPE_COLLECTOR_START(注册的规则);}
//规则1.h
#包括“注册规则.h”
名称空间您的_名称空间{class rule1{};}
名称空间tao_pegtl_名称空间{REGISTER_RULE(您的名称空间::rule1);}
//规则2.h
#包括“注册规则.h”
名称空间您的_名称空间{class rule2{};}
名称空间tao_pegtl_名称空间{REGISTER_RULE(您的名称空间::rule2);}
//规则集合.h
名称空间tao_pegtl_名称空间{
类型\u收集器\u端(注册的\u规则);
结构规则_集合:templateClass{}
}

这不允许您拥有一个包含所有操作专门化的不同文件(您称之为SpecificTemplate.h)。我不知道什么是
tao::pegtl
,所以我可能完全不在这里。

您能详细说明为什么只需指定
template struct specificClass{/*执行相同的操作*/}
?如果所有这些实例化都是相同的,那么我看不出将每个实例化都拼出来的目的。如果它们不同,
如何从注册的
中创建类?知道要更改什么吗?因为/*执行相同的操作*/会对t本身做一些事情。比如调用t.method()。这对于所有类都是一样的,但必须针对语法框架进行具体实例化。您可以直接使用
T.method()
很好(如果所有类都有
method()
)…也许您可以使示例更具体一些?所以您需要的是
template <unsigned long N> struct version : version<N - 1> {};
template <> struct version<0> {};
// the result is stored in this type
template <class... Ts>
struct list {
    template <class T>
    using add = list<Ts..., T>;
};

// macro TYPE_COLLECTOR_START usage will expand to
auto get(version<0>) -> list<>;

// macro TYPE_COLLECTOR_ADD usages will expand to
auto get(version<1>) -> decltype(get(version<0>{}))::add<int>;
auto get(version<2>) -> decltype(get(version<1>{}))::add<std::pair<bool, bool>>;
auto get(version<3>) -> decltype(get(version<2>{}))::add<char>;

// macro TYPE_COLLECTOR_END usage will expand to
using foo = decltype(get(version<3>{}));
#define REGISTER_RULE(rule)\
    TYPE_COLLECTOR_ADD(registered_rules, rule)\
    \
    template <>\
    struct Action<rule_name> {\
        static void apply0(State& state) {\
            state.rule = rule_name::ID;\
        }\
    }
// registered_rules.h
namespace tao_pegtl_namespace { TYPE_COLLECTOR_START(registered_rules); }

// rule1.h
#include "registered_rules.h"
namespace your_namespace { class rule1 {}; }
namespace tao_pegtl_namespace { REGISTER_RULE(your_namespace::rule1); }

// rule2.h
#include "registered_rules.h"
namespace your_namespace { class rule2 {}; }
namespace tao_pegtl_namespace { REGISTER_RULE(your_namespace::rule2); }

// rules_collection.h
namespace tao_pegtl_namespace {
    TYPE_COLLECTOR_END(registered_rules);
    struct rules_collection : templateClass<(unpack `registered_rules`...)> {}
}