将模板原型作为模板参数传递——这可能吗?

Passing template prototype as template argument - is it possible?

首先,对术语表示歉意 - 我不确定模板原型是否是正确的术语。我的意思是:

template <class T, class X>
class TemplatePrototype
{
 // code
};

我有一个函数,它根据该函数的模板参数创建一个模板对象。

template <class T, class X>
void doSomething()
{
    TemplatePrototype<T, X> aTemplateTX;
    aTemplateTX.doSomethingElse();
}

但是TemplatePrototype有15种不同的版本,它们的接口相同但执行不同(TemplatePrototype由另一个库提供)。结果,我有很多代码看起来像这样:

template <class T, class X>
void doSomethingWithOne()
{
    TemplatePrototypeOne<T, X> aTemplateTX;
    aTemplateTX.doSomethingElse();
}

template <class T, class X>
void doSomethingWithTwo()
{
    TemplatePrototypeTwo<T, X> aTemplateTX;
    aTemplateTX.doSomethingElse();
}

由于架构的原因,我必须知道我将使用哪个TemplatePrototype 之前我知道实际类型T和X. 我会喜欢看到这样的东西:

template <class T, class X, class Prototype>
void doSomething()
{
    Prototype<T, X> aPrototype;
    aPrototype.doSomething();
}

但是我预先指定了模板参数的一部分 - 即我在知道 T 和 X 之前指定原型。显然,这在 C++ 中是不可能的。

同样,我不能将原型作为模板参数传递,因为它仍然会导致大量重复代码。

一些重要事实:我知道所有可能输入的范围。

所以理论上我可以使用宏来定义每个可能的模板特化并将它们插入到容器中,然后我将使用它来访问我需要的特化。但是,我正在寻找一个更 'elegant' 的解决方案 - 是否可以传递模板原型而不将它们专门化为模板的参数 class,然后在调用函数时稍后实例化?示例:

template <class Prototype>
class Holder
{
    template <class T, class X>
    void doSomething()
    {
        Prototype<T, X> aPrototype;
        aPrototype.doSomethingElse();
    }
};

据我所知这是不可能的,但我想知道 SO 社区是否有一些人知道解决方案?

编辑:

所以我已经将此作为我的解决方案实施,感谢以下答案!

#include <iostream>

template <typename T>
struct Foo
{
        Foo() { aPtr = 0; }
        T* aPtr;
};

template <template<typename> class C>
struct Bar
{
        template <class T>
        void doSomething()
        {
                C<T> aClass;
                if (aClass.aPtr)
                        std::cout << "Hello world" << std::endl;
        }
};


int main()
{
        Bar<Foo> aFoo;
        aFoo.doSomething<int>();

        return 0;
}

这使我能够指定我希望使用的 TemplatePrototype,之前我可以知道模板参数。

是,使用模板模板参数,例如

template <typename T>
struct Foo
{
};

template <template<typename> class C>
struct Bar
{
};

然后

Bar<Foo> b;

您正在寻找模板模板参数

在模板参数列表中,而不只是:

class TemplatePrototype

将您的原型指定为 class 模板,该模板本身有两个模板类型参数(此处不给它们命名),例如:

template<class,class> class TemplatePrototype
//^^^^^^^^^^^^^^^^^^^

这将产生如下函数:

template <class T, class X,
          template<class,class> class TemplatePrototype>
void doSomething()
{
    TemplatePrototype<T, X> aTemplateTX;
    aTemplateTX.doSomethingElse();
}

调用示例:

doSomething<T, X, TemplatePrototypeOne>();

要独立于传递给 "prototype" 的模板参数数量(此处为 2,即 TX),您可以使用可变参数模板(因为C++11).

为此,首先将原型模板参数移动到第一个位置:

template <template<class,class> class TemplatePrototype,
          class T, class X>

然后,将class T, class X替换为class ...Ts,这是一个任意数量的类型参数的占位符。另外,在模板模板参数列表中,将 class,class 替换为 class...。并在函数实现内的实例化中,将<T, X>替换为<Ts...>到"expand"参数包。

结果如下所示:

template <template<class...> class TemplatePrototype,
          class ... Ts>
void doSomething()
{
    TemplatePrototype<Ts...> aTemplateTs;
    aTemplateTs.doSomethingElse();
}

Live demo