C++模板中实例化和特化的区别

54
在C ++模板的上下文中,专门化和实例化有什么区别?从我到目前为止所读到的内容来看,以下是我对专门化和实例化的理解。
template <typename T>
struct Struct
{

     T x;
};

template<>
struct Struct <int> //specialization
{

    //code
};

int main()
{
   Struct <int> s; //specialized version comes into play
   Struct <float> r; // Struct <float> is instantiated by the compiler as shown below

}

编译器实例化 Struct <float>
template <typename T=float>
struct Struct
{
    float x;
}

我的理解中,模板实例化和特化的正确性如何?
6个回答

60

(隐式)实例化

这就是你所说的实例化(如问题中所提到的)。

显式实例化

这是当您告诉编译器使用给定类型来实例化模板时,就像这样:

template Struct<char>; // used to control the PLACE where the template is inst-ed

(显式) 特化

这就是你所说的特化(在问题中提到)。

部分特化

这是当你为一个类型子集给出模板的另一种定义时的情况,例如:

template<class T> class Struct<T*> {...} // partial specialization for pointers

9
在C++标准中(但其他地方没有),还有隐式特化,这是编译器在实例化模板且未选择显式特化时执行的操作。 - Sebastian Redl
如果您有相关的引用资料,强烈建议提供。 - Gab是好人
1
你的回答非常有帮助;我还想提一下 https://dev59.com/2HE95IYBdhLWcg3wWMdQ#2351155 -- 关于共享库存在一些注意事项,因为据我所知,在一个库中未使用的实例会被剥离,而另一个引用该实例的库则信任它将在链接过程中的某个时刻得到解决。结果是一个相当误导性的“未定义引用”,除非你在头文件中进行实例化。我曾经认为这个错误意味着我必须提供每个显式特化! - John P

24
在C++模板的上下文中,专业化和实例化有何区别?
通常情况下(没有专业化),编译器将在使用时创建模板的实例化,通过用实际模板参数(例如您的示例中的int)替换形式模板参数(T),然后编译生成的代码。
如果存在专业化,则对于由该专业化指定的特殊模板参数集,应使用该专业化的实现,而不是编译器将创建的内容。

14

概述

  • 特化: 当你将模板参数替换为一个类或函数模板的模板参数时,得到的类、函数或类成员。

  • 实例化: 将模板或类模板成员创建为特化的操作。特化可以由部分特化、类模板成员或基本类或函数模板创建出来。

显式特化是指在没有实例化的情况下明确定义类、函数或成员。


是类模板成员还是模板类成员? - Dan Nissenbaum
另外,也许在给出完整答案的基础上,您可以添加两个附加的项目符号,并提供示例。 - Dan Nissenbaum
@DanNissenbaum,“class [template member]” 也是“部分特化...或主类或函数模板”,因此包含在其中。我原本想说的是“[类模板]成员”。这些不是模板,因此我的措辞是“模板或类模板成员”。 - Johannes Schaub - litb
第一个项目中提到的应该是“类成员”,而不是“类模板成员”(这是标准在定义“特化”时使用的术语)。 - Johannes Schaub - litb

13

模板特化实际上可以为特定类型更改模板的行为。例如将其转换为字符串:

template<typename T> std::string convertToString( const T& t )
{
   std::ostringstream oss;
   oss << t;
   return oss.str();
}

如果我们的类型已经是std::string,那么让我们专门处理它,因为通过ostringstream是毫无意义的。

template<> std::string convertToString( const std::string & t )
{
   return t;
}

你可以为类进行专门化。
现在来说实例化:这是为了让你将某些类型的编译移动到一个编译单元中。这既可以节省编译时间,有时还可以减少代码膨胀。假设我们将上面的内容改成一个名为StringConvert的类,而不是一个函数。
template<typename T>
class StringConvert
{
 public:
  // 4 static functions to convert from T to string, string to T,
   // T to wstring and wstring to T using streams
 };

我们需要将许多整数转换为字符串,以便我们可以实例化它:将其放置在一个头文件中。
 extern template class StringConvert<int>;

将此放入一个编译单元中:

 template class StringConvert<int>;

请注意,上述操作也可以使用实际未实现内联的函数(无需在头文件中添加extern)完成。您的编译单元之一将实现它们。但是,这样模板仅限于已实例化的类型。有时在模板具有虚析构函数时执行此操作。

请注意,我的专业化示例并不是一个很好的示例,因为它是一个函数,所以你可以重载它。但是,如果你需要在类模板中执行此操作,就应该这样做,例如,你有一些用于类型的特性类,其中之一是将其转换为字符串。仅出于演示目的,通过该函数展示为什么要为某个类型进行专门化更容易理解。 - CashCow

10

在 c++ 11 中。

实例化:

使用给定的模板参数实例化模板。

template <typename T>
struct test{ T m; };

template test<int>;//explicit instantiation

这会导致定义一个名为test<int>的结构体。

test<int> a;//implicit instantiation

如果模板template <typename T> struct test之前已经被实例化为参数T = int(显式或隐式),则它只是一个结构体实例化。否则,它将首先隐式地使用参数T = int实例化template <typename T> struct test,然后再实例化结构体test<int>
专门化:
专门化仍然是一个模板,您仍然需要实例化才能获取真正的代码。
template <typename T>
struct test{ T m; };
template <> struct test<int>{ int newM; } //specialization

模板特化中最有用的可能是您可以为不同的模板参数创建不同的模板,这意味着您可以为不同的模板参数定义不同的类或函数

template<> struct test<char>{ int cm; }//specialization for char
test<char> a;
a.cm = 1;

template<> struct test<long> { int lm; }//specialization for long
test<long> a;
a.lm = 1;

除了上面提到的完全模板特化外,还存在部分模板特化(仅适用于类模板)。
template<typename T>
struct test {};
template <typename T> struct test<const T>{};//partial specialization for const T


template <typename A, typename B>
struct test {};
template <typename B> struct test<int, B>{};//partial specialization for A = int

这里有一个错误:template test<int>;,你必须添加关键字 struct - Itachi Uchiwa

0
一个专门的模板不再只是一个模板。相反,它要么是一个实际的类,要么是一个实际的函数。
特化可以来自实例化或显式特化,参见下面的14.7.4。
实例化基于主模板定义。一个示例隐式类模板实例化,
template<typename T>
class foo {}

foo<int> foo_int_object;

一个示例显式类模板实例化,
template class foo<double>;

显式特化与其主模板有不同的定义。

template<>
class foo<bool> {}

// 标准摘录

14 模板

14.7 模板实例化和特化

4 已实例化的模板特化可以根据给定的参数列表隐式实例化(14.7.1),也可以显式实例化(14.7.2)。特化是一个类、函数或类成员,它可以被实例化或显式特化(14.7.3)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接