嵌套模板参数

时间:2014-11-13 14:23:25

标签: c++ templates

我开始阅读模板,我发现智能指针使用双模板,如下所示:

template <class T>
class myclass
{
public:
   template <class U>
   myclass(U* q) { /* ... */ }
};
那是什么意思?我知道模板化函数会推导U,如

myclass(new whatever(3));

其中Uwhatever*。那么T是什么? UT之间的关系是什么?

我很困惑......

4 个答案:

答案 0 :(得分:5)

以上示例代码与TU之间没有任何关系。

一个是传递给类模板myclass的类型参数,另一个是传递给构造函数的推导类型。

然而,你找到它的地方(可能在std::shared_ptr中)会变得更有趣。

现在,在std::shared_ptr中,构造函数的主体强制要求U是来自T的后代类型。该构造函数允许您从std::shared_ptr<Base>创建Derived*,同时在构造函数中知道它是从Derived*构造的。

我们为什么要这样?毕竟,Derived*可以在构造函数之外转换为Base*,那么为什么不采用T*(又名Base*)?

嗯,std::shared_ptr<T>是捆绑在一起的3件事。它是T*,参考计数器和清理功能(“删除器”)。

当引用计数减少为0时,将调用清除函数。默认情况下,cleanup函数调用指向对象的析构函数。

但是哪个析构函数?好吧,调用的析构函数基于类型U T。在构造时,编写一个知道静态类型U的销毁函数。此销毁功能会被转移到原始shared_ptr<T>的所有副本,因此即使它被远处销毁,它仍然会调用~U而不是~T

如果T有一个virtual ~T(),这没什么用(事实上,相同的comdat折叠或类似的技术会使它什么都不做),但是如果它有一个非虚拟的析构函数, shared_ptr将调用正确的析构函数(假设类型实际为U而不是某些派生类型的U)。

shared_ptr需要存储销毁函数以用于其他原因(您可以传递自定义销毁函数),因此这不会产生很大的开销。

答案 1 :(得分:1)

在您的示例中,myclass模板类,构造函数myclass::myclass()模板方法。两者都必须有一个类型,以便他们可以&#34;工作&#34;正确地,在哪里&#34;给予&#34;也可能意味着推断出类型。

例如myclass实例的有效声明是

myclass<double> x(new int(3));

此处T = doubleU = int(请注意构造函数采用U*)。不需要在UT之间建立关系。

答案 2 :(得分:0)

TU之间没有任何关系。您可以使用任何myclass实例化T并使用任何参数调用构造函数,只要它是指针(在您的情况下):

class A {};
class B {};
myClass<A> x(new B()); // T == A, U == B

请注意,您无法明确指定U,只能从参数中推断出来。

答案 3 :(得分:0)

考虑一个类模板:

template<typename T>
class Element
{
    T _element;
public:
    CopyFrom(T t);
};

如果您想CopyFrom T的任何类型,该怎么办?例如:

Element<int> a;
a.CopyFrom(10.0f);

此处,仅仅为了理解intfloat转换是不可能的,只有CopyFrom可以做到(使用一些辅助函数,一些其他内部重载函数等) - 但是避免任何数据丢失警告。因此,您需要以下内容:

a.CopyFrom<float>(10.0f);

在这里,您将参数类型指定为float - 编译器现在会很高兴。为了使其有效,您需要使CopyFrom成为一个函数(方法)模板:

public:
        template<typename U>
        CopyFrom(U t);

现在,a的类型为Element<int>,但CopyFromCopyFrom<float>。显然,您不需要使用<float>

a.CopyFrom/*<float>*/(10.0f); // Element<int>::CopyFrom<float>(...);