动态选择模板专业化

时间:2014-06-23 11:55:19

标签: c++ templates c++03

我有一个模板类Filter,它将另一个模板类Model的实例作为参数。我现在希望拥有vector个不同的模型(即具有不同模板参数的Model),并且能够在每个模型上运行Filter。为此,我从非模板Model派生class AbstractModel,这允许我将这些不同的模型放入单个vector中。一切都很好,但是有一个问题:调用模板类的方法需要静态地知道模板参数。但我并不知道它们是静态的。

这是代码

#include <vector>
#include <cstdlib>

class AbstractFilterData {};
class AbstractModel {};
template<int N>
class Args {};

template<int N>
class FilterData : public AbstractFilterData
{ int a; };

template<int N>
struct Model : public AbstractModel
{
    static const int n=N;
    virtual void compute(Args<N>& args) const = 0;
};

struct ModelA : public Model<3>
{
    virtual void compute(Args<3>& args) const {}
};

struct ModelB : public Model<5>
{
    virtual void compute(Args<5>& args) const {}
};

template<int N, int P>
struct Filter
{
    static void predict(FilterData<N>& data, const Model<N>& model)
    {
        Args<N> args;
        model.compute(args);
    }
};

int main()
{
    // For statically-defined model this works OK
    FilterData<ModelA::n> data;
    ModelA modA;
    Filter<ModelA::n,2>::predict(data, modA);

    // Let's make a bunch of different models and put them into a vector
    std::vector<AbstractModel*> models;
    models.push_back(new ModelA);
    models.push_back(new ModelB);

    // Associated data for these models
    std::vector<AbstractFilterData*> fdata;
    fdata.push_back(new FilterData<ModelA::n>);
    fdata.push_back(new FilterData<ModelB::n>);

    for(size_t i=0; i<models.size(); ++i)
    {
        // Now I'd like to run Filter::predict() on
        // each of the models in the vector... but how?
        Filter<models[i]->n,2>::predict(*fdata[i], *models[i]);
        // This breaks on models[i]->n being not a constant-expression, of course
    }
}

我可以考虑对模型模板参数的可能值k进行循环,然后尝试dynamic_cast(models[i],Model<k>*),然后调用Filter<k,2>::predict(),但这看起来很难看。另外,由于我不知道k的上限,我不得不猜测,因为INT_MAX Filter实例化会使代码无法使用。

另一种方法可能是在Filter<N,2>::predict()声明中为Model<N>方法添加一个静态const指针,但这也很丑陋,因为类Model似乎与类{{{}}相关联1}},它打破了这些类的独立性(例如,添加另一个过滤器不仅起作用)。

是否有更好的方法来遍历这些不同模型并在其上调用Filter?理想情况下,我希望编译器能够为我完成所有调度工作,因此对于从未真正使用的参数,不会发生模板实例化。

1 个答案:

答案 0 :(得分:0)

这是伪代码,省略了很多东西。

class AbstractModel {
    virtual int Order() = 0;
};
class AbstractModel {
    virtual int Order() = 0;
};

template<int N>
class FilterData : public AbstractFilterData {
    virtual int Order() { return N; };
}
template<int N>
class Model : public AbstractModel {
    virtual int Order() { return N; };
}

multimap<int, AbstractFilterData*> dataMap; // dataMap[i] contains a pointer to 
                                            // FilterData<i> 
multimap<int, AbstractModel*> modelMap;     // modelMap[i] contains a pointer to 
                                            // Model<i>

现在你可以做很多事情。您可以将AbstractFilterData*传递给compute,然后根据需要向下转发参数。您可以将整个dataMap传递给compute,它将获取和转发所需的数据。您可以在仅包含模板成员的类中隐藏dataMap

template <int N>
void Put(FilterData<N>);
template <int N>
FilterData<N> Get();  // or perhaps FilterDataIterator<N>, if you really
                      // need a multimap

并完成所有的演员本身,然后绕过那个班级。或者你可以改变整个事情并用modelMap做同样的事情。