嵌套模板参数

Nested template parameters

本文关键字:参数 嵌套      更新时间:2023-10-16

我已经开始阅读有关模板的文章,我发现智能指针使用双模板,如下所示:

template <class T>
class myclass
{
public:
   template <class U>
   myclass(U* q) { /* ... */ }
};

这是什么意思?我知道模板化函数会推断出U ,因为

myclass(new whatever(3));

U将在哪里whatever*.那么什么是TUT之间有什么关系?

我很困惑...

上面的示例代码在TU之间没有强加任何关系。

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

但是,在您发现它的地方(可能std::shared_ptr)它会变得更加有趣。

现在,在std::shared_ptr中,构造函数的主体强加了一个要求,即UT的后代类型。 该构造函数允许您从Derived*创建std::shared_ptr<Base>,同时在构造函数中知道它是从Derived*构造的。

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

好吧,std::shared_ptr<T>是将 3 件事捆绑在一起。 它是一个T*,一个引用计数器和一个清理功能("删除器")。

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

但是哪个析构函数? 好吧,调用的析构函数基于类型 U而不是 T 。 在构造时,编写一个知道静态类型的破坏函数U 。 这个销毁函数被带到该原始shared_ptr<T>的所有副本中,所以即使它被销毁得很远,它仍然调用~U而不是~T

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

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

在您的

示例中,myclass是一个模板类,构造函数myclass::myclass()是一个模板方法。两者都必须被赋予一个类型,以便它们可以"正常工作",其中"给定"也可能意味着推断出该类型。

例如,myclass实例的有效声明是

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

这里T = doubleU = int(请注意,构造函数采用U*)。UT之间不需要有关系。

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

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

请注意,您不能显式指定U,它只能从参数中推导出来。

考虑一个类模板:

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

如果要CopyFrom任何T的类型怎么办。例如:

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

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

a.CopyFrom<float>(10.0f);

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

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

现在,a属于 Element<int> 型,但CopyFrom将是CopyFrom<float>。显然,您无需使用 <float> .

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