C ++从模板参数类型生成包含switch / map的函数体

时间:2012-02-29 21:25:30

标签: c++ templates metaprogramming

我希望修改现有的模板类。类的模板参数是(半)变量,我想用它们来生成像函数体一样的条件/开关/映射。

我的编译器不支持可变参数模板,因此(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”的类型数量会更高。

有人能让我知道可以实现的任何技术吗?

我已经依赖于提升。我的编译器相当新(但不支持可变参数模板)。我宁愿不采取任何新的依赖关系或引入更多的复杂性而不是必需品。

2 个答案:

答案 0 :(得分:4)

我以前写过这样的代码,所以我可以告诉你这是可能的。 (这是为了商业,闭源工作,所以我担心我不能告诉你代码)。您可以在Boost.Variant库中找到一个非常好的示例,特别是http://svn.boost.org/svn/boost/trunk/boost/variant/detail/visitation_impl.hpp。代码是非常密集和高级的C ++,所以可能需要一两天才能彻底理解它。

快速摘要:boost::variant类模板的工作方式类似于一个带有int的联合,它存储了union的哪个成员有效。 “访问”功能允许您提供一个带有重载operator()的函数对象,它可以接受任何可能的联合成员,并生成一个switch语句,该语句访问相应的成员并调用右{{1}过载就好了。如果您已经发现这很复杂,或者您还不了解Boost.MPL,我建议您不要在这里阅读,阅读Boost.Variant文档,然后重写您的类以便能够使用它:聪明Boost的家伙们已经为你完成了这项工作。它只是标题,所以如果你已经在使用Boost,那么对你没有新的依赖。

此文件负责生成switch语句。简而言之,它有两种替代实现。第一个(第72-90行)使用递归模板operator(),其作用类似于您可能已经看作模板元编程示例的阶乘函数。非特定模板以递归方式调用列表中的下一个(visitation_impl_step)。一旦扩展出所有模板,生成的代码看起来有点像函数function0,function1和c的一系列函数。像这样:

typename mpl::next<Iter>::type

第二个实现(第193-285行)使用Boost.PP预处理器魔术库来生成一个类似于你想要的switch语句,其中result_type functionN(variant vnt, visitor vr) { if (v.which == N) return vr(static_cast<Nth type>(vnt.value)); else functionN-1(vnt, vr); } 可能有多少个案例。每个案例的主体是对模板功能的调用(第120-185行),它在第N个类型上生成对访问者的调用。此实现中的大多数复杂性来自于必须担心在boost::variant内备份值,以便在访问者或任何相关构造函数抛出时保留强大的异常保证。

即使您决定采用其他方式,我也建议您阅读并理解Boost.Variant源代码,作为学习练习。它将重新定义您对C ++中可能(以及什么是明智的)的想法!

答案 1 :(得分:0)

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

如果要对模板参数中指定的每种类型的实例执行某些操作,则必须实现递归模板功能。有关详细信息,请参阅this question