多个模板<int>函数的专业化

时间:2015-06-25 22:57:32

标签: c++ templates

我正在运行模拟,要求我使用int参数的模板(D =我系统的维度)。典型的模拟功能是

template <int D> void simulation();

当我想专门化这个模板时,我使用了一个开关

switch(d){
case 2:
    simulation<2>();
    break;
case 3:
    simulation<3>();
    break;
// etc.
}

据我有一个模拟功能,没关系。但想象一下我有10个(simul1,simul2,... simul10),d可以从2到10。我必须写十次相同的开关!

我想知道是否有可能将其分解,并且有类似的东西:

template <void (*fun)()> runSimulation(int d){
    switch(d){
    case 2:
        fun<2>();
    }
}

当然<void (*fun)()>没有做我想要的,因为funtemplate<int>。有办法吗?

3 个答案:

答案 0 :(得分:2)

当您可以使用静态方法将模拟函数更改为类时:

struct sim1
{
    template<int D> static void apply();
};

然后应该有以下工作:

template <typename Sim> runSimulation(int d){
    switch(d){
    case 2:
        Sim::template apply<2>();
    case 3:
        Sim::template apply<3>();
    // ...
    }
}

哪个是通用的,可以使用runSimulation<sim1>(d);runSimulation<sim2>(d);等来调用

答案 1 :(得分:0)

这是一个使用模板递归将运行时信息转换为编译时信息的简单方案:

template<int N> void runSimulation() { std::cout<<"runSimulation " << N << std::endl; }

constexpr size_t max_index = 100;

namespace detail
{
   //overload for maximum index
    void callSimulation_impl(size_t i, std::integral_constant<size_t, max_index>) {}

    template<size_t N>
    void callSimulation_impl(size_t i, std::integral_constant<size_t, N>)
    {
        if(i==N)
        {
            runSimulation<N>();
        }
        else
        {
            callSimulation_impl(i, std::integral_constant<size_t, N+1>());
        }
    }
}

void callSimulation(size_t i)
{
    detail::callSimulation_impl(i, std::integral_constant<size_t, 0>());
}

int main(int argc, char *argv[])
{
    callSimulation(10);                  // calls runSimulation<10>();

    //or also:

    callSimulation(rand()%max_index);    //calls a random simulation
}

DEMO

正如您生成的手动切换一样,它需要按照传递索引的大小线性努力(使用二进制搜索也可以实现类似的算法实现)。

如果效率很重要,您也可以使用魔术开关进行O(1)工作,请参阅herehere - 我&#39;马云的粉丝。

编辑:此方案可与@Daniel Frey的其他答案结合使用,以便为多种模拟类型和任意多种切换案例提供单一功能。

答案 2 :(得分:0)

如果C ++接受模板函数作为模板参数会很好,但我不知道如何表达它。但是,它接受模板类作为模板参数。

如果您愿意将您的模拟系列(simul1,simul2等)打包成每个系列的一个包装模板(Wrapper1,Wrapper2,...),您可以执行以下操作:

template<template<int D> class SimulationFunctionWrapper> struct Caller {
    static void simulation(int d) {
        switch(d) {
            case 2: SimulationFunctionWrapper<2>::run(); break;
            case 3: SimulationFunctionWrapper<3>::run(); break;
        }
    }
};

#include <iostream>

// normal simul1 declarations and definitions
template<int D> void simul1();
template<> void simul1<2>() { std::cout << "simul1<2>\n"; }
template<> void simul1<3>() { std::cout << "simul1<3>\n"; }

// Enables dispatching to the right simul1 based on the template integer
template<int D> struct Wrapper1 { static void run() { simul1<D>(); } };

// normal simul2 declarations and definitions
template<int D> void simul2();
template<> void simul2<2>() { std::cout << "simul2<2>\n"; }
template<> void simul2<3>() { std::cout << "simul2<3>\n"; }

// Enables dispatching to the right simul2 based on the template integer
template<int D> struct Wrapper2 { static void run() { simul2<D>(); } };

int main(int argc, const char *argv[]) {
    Caller<Wrapper1>::simulation(argc);
    Caller<Wrapper2>::simulation(argc);
    return 0;
}

这显示了如何使用相同的代码(Caller)来决定调用哪个函数。不幸的是,它需要样板包装器。