模板派生自模板

时间:2013-04-14 12:52:55

标签: c++ templates

给定两个非常相似但行为不同的模板化类:

template<class T>
firstBase {};

template<class T>
secondBase {};

现在我有了这个其他类,基于它的模板参数,它将来自firstBase或来自secondBase

template<class B, class T>
myClass : public B<T> { /* T is used in here */ };

嗯,这不起作用。编译器告诉我B是一个未知的模板名称。 (error: unknown template name 'B'

我目前的解决方法是将myClass定义为

template<class B, class T>
myClass : public B { /* T is used in here */ };

并且myClass的来电者需要通过myClass<b<t>, t>而不是myClass<b, t>来取消它。

后者非常好,可以减少一些复制和粘贴代码。有没有其他方法可以实现这个目标?


在我的用例中,我正在尝试为pimpl习语实现deep_const_ptr,以启用'true constness'。根据{{​​1}}是否需要复制 - 可分配,它可以使用myClassdeep_const_ptr<std::shared_ptr>作为其私有指针。

deep_const_ptr<std::unique_ptr>

修改
因此,我按照Luc Danton in his answer的建议,将#include <memory> #include <iostream> template<class pointerT, class typeT> class deep_const_ptr : public pointerT { public: explicit deep_const_ptr(typeT* ptr) : pointerT(ptr) { } // overloading pointerT::operator->() for non-constant access typeT* operator->() { std::cout << "deep_const_ptr::operator->()" << std::endl; return pointerT::operator->(); } // overloading pointerT::operator->() for constant access const typeT* operator->() const { std::cout << "deep_const_ptr::operator->() const" << std::endl; return pointerT::operator->(); } }; std::unique_ptr<myClass::Private>传递给我的自定义std::shared_ptr<myClass::Private>

deep_const_ptr

5 个答案:

答案 0 :(得分:2)

你想要的是template template parameter

//       vvvvvvvvvvvvvvvvvv
template<template<typename> class B, class T>
class myClass : public B<T> { /* T is used in here */ };

然后,使用它:

myClass<firstBase,int> myIntClassObject;
myClass<secondBase,bool> myBoolClassObject;

对于std::unique_ptr,您可以创建一个包装器:

template<typename T>
class uniquePtr : public std::unique_ptr<T>
{
};

template<typename T>
using uniquePtr = std::unique_ptr<T>;

答案 1 :(得分:1)

B应该是模板模板参数:

template<template <class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };

现在您可以将firstBasesecondBase作为第一个模板参数,因为它们是模板。

答案 2 :(得分:1)

您只需使用template-template parameter即可使其发挥作用:

template <
    template <class> class B, class T>
//  ^^^^^^^^^^^^^^^^
class myClass : public B<T> { / ... / };

答案 3 :(得分:1)

您需要的是模板模板参数:

template<template<class> class B, class T>
//       ^^^^^^^^^^^^^^^
class myClass : public B<T> { /* T is used in here */ };

现在,myClass类模板的第一个模板参数必须是一个接受一个模板(类型)参数的类模板。所以,把所有东西放在一起:

template<class T>
class firstBase {};

template<class T>
class secondBase {};

template<template<class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };

以下是如何实例化myclass模板以创建派生自firstBase<int>的类:

myClass<firstBase, int> obj;

最后,这是一个live example

答案 4 :(得分:1)

我建议一般不要使用模板模板参数。例如,std::unique_ptrstd::shared_ptr的不同之处在于前者接受两个类型参数而后者只接受一个。所以如果你声明例如template<template<typename> class B, typename T> class foo;然后foo<std::shared_ptr, int>有效,但foo<std::unique_ptr, int>不是。

在您的特定情况下,您可以使用template<typename...> class B作为参数,因为这种模板模板参数是特殊的。但是,这只接受仅采用类型参数的模板(甚至不是模板模板参数)。有时这可以使用别名模板解决,有时它不能。

根据我的经验,有更好的选择 - 例如你可以有条件地继承:

template<typename T>
struct pointer: std::conditional</* Make a choice here*/, std::unique_ptr<T>, std::shared_ptr<T>>::type {};

或者为什么不接受智能指针作为参数本身:

template<typename Pointer>
struct foo {
    Pointer pointer;
    /* typename Pointer::element_type plays the role that T used to have */
};

标准库本身采取了一些措施来避免模板模板参数:您是否注意到std::vector<T>使用std::allocator<T>作为参数,而不是std::allocator?作为权衡,这意味着分配器必须提供rebind成员别名模板。