C++从模板参数类型生成包含开关/映射的函数体

C++ generate function body containing switch/map from template argument types

本文关键字:开关 包含 映射 函数体 参数 类型 C++      更新时间:2023-10-16

我想修改现有的模板化类。该类的模板参数是(半(变量,我想使用它们来生成类似条件/开关/映射的函数体。

我的编译器不支持可变参数模板,因此(boost(预处理器当前用于生成现有类:

template <typename item0, typename item1, typename item2 ..., typename itemN>
struct myclass { /*various operations*/ };

需要一个新的函数 func,它将在运行时查询变量并返回作为模板参数之一的对象。

例:

template <typename item0, typename item1, typename item2 ...>
struct my_class { 
    //...various operations
    //automatic generatation possible?
    std::string * func()
    {
        string s;
        while(data) {
        switch (data[0])
        {
            case item0::id:
                s += item0::get_name();
            case item1::id:
                s += item1::get_name();
            //... for each template arguemnt typename where typename is no void
        }
        }
        return s;
    }
 };
typedef my_class<a, b, c> class_one;
typedef my_class<d, e, f> class_two;
typedef my_class<a, b, c, x, y, z>  class_three;
 int main()
 {
    ...
    class_one test;
    test.func();
    ...
 }

我想生成func((的内容,因为项目的数量会很多,而"myclass"的类型数量会更高。

有人可以告诉我任何技术如何实现这一目标吗?

我已经依赖提升了。我的编译器相当新(但不支持可变参数模板(。我宁愿不采用任何新的依赖项或引入比必要更复杂的内容。

我以前写过这样的代码,所以我可以告诉你这是可能的。(这是用于商业的闭源工作,所以我恐怕不能向你展示代码(。你可以在 Boost.Variant 库中找到一个非常好的示例来说明如何做到这一点,特别是 http://svn.boost.org/svn/boost/trunk/boost/variant/detail/visitation_impl.hpp 。代码非常密集且C++高级,因此可能需要一两天才能彻底理解它。

快速摘要:boost::variant类模板的工作方式类似于一个联合,带有一个 int 存储联合的哪个成员是有效的。"visitation"功能允许您为函数对象提供重载operator(),该可以采用联合的任何可能成员,并生成一个 switch 语句,该语句访问适当的成员并调用其上的右operator()重载。如果你已经发现这很复杂,或者你还不了解Boost.MPL,我建议你停止阅读这里,阅读Boost.Variant 文档,然后重写你的类以便能够使用它:Boost的聪明人已经为你完成了工作。它是仅标头的,因此如果您已经在使用 Boost,则没有新的依赖项。

此文件负责生成 switch 语句。简而言之,它有两种替代实现。第一个(第 72-90 行(使用递归模板visitation_impl_step其工作原理类似于您可能已经看到的模板元编程示例的阶乘函数。非专用模板递归调用列表中的下一个模板 (typename mpl::next<Iter>::type (。一旦所有模板都展开,生成的代码看起来有点像一系列函数 function0、function1 等,如下所示:

result_type functionN(variant vnt, visitor vr) {
    if (v.which == N)
        return vr(static_cast<Nth type>(vnt.value));
    else
        functionN-1(vnt, vr);
}

第二个实现(第 193-285 行(使用 Boost.PP 预处理器魔术库生成一个 switch 语句,就像你想要的一样,具有boost::variant可能具有的尽可能多的情况。每个案例的主体都是对模板函数(第 120-185 行(的调用,该函数生成对第 N 个类型的访问者的调用。此实现中的大部分复杂性来自于必须担心在variant中备份值,以便在访问者或任何涉及的构造函数抛出时保留强异常保证。

即使您决定以另一种方式执行此操作,我也建议您阅读并理解 Boost.Variant 源代码,作为学习练习。它将重新定义您对C++中可能(以及明智

(的想法!
编译器

将能够使用精确的模板定义生成代码。无法强制编译器在 switch 语句中生成其他情况或根据模板参数生成循环的其他迭代。

如果要对模板参数中指定的每种类型的实例执行某些操作,则必须实现递归模板函数。详情请参考本问题。