默认模板参数和部分特化

64
请解释一下为什么以下代码片段可以编译并且完美运行。 我感到很困惑。
#include<iostream>
template<class A = int, class B=double>
class Base
{};

template<class B>
class Base <int, B>
{
public:
  Base()
  {
     std::cout<<"it works!!!!!\n";
  }
};

int main()
{
  Base<> base; // it prints "it works!!!!!"
  return 0;
}

它不该属于模板类Base的通用形式吗?


23
谢谢你教我默认参数会适用于特化版本,给你点赞。 - chris
+1 几乎和 @chris 说的原因一样。完全没有想到。 - WhozCraig
1
我同意。这是一个非常好的问题,提问得非常好,包括用 SSCCE 进行了完整的描述,同时也描述了实际和期望的行为。干得好! - Jerry Coffin
4个回答

44

默认参数适用于特化——事实上,特化必须接受(可以这么说)基模板的默认参数。在特化中尝试指定默认值:

template<class A = int, class B=double>
class Base
{};

template<class B=char>
// ...

出现了错误。

同样,如果我们更改特化,使其专门为基础模板所提供的默认类型之外的其他类型进行特化:

template<class A = int, class B=double>
class Base
{};

template<class B>
class Base <char, B>

...那么基础模板将会被选择。

因此,正在发生的是:首先选择模板参数的类型。在这种情况下(在实例化时未指定类型),两个类型都基于基础模板中指定的默认模板参数。

然后(作为基本上是分开的一步),它会对所有符合这些参数类型的模板执行类似于重载分辨率的模拟。像重载分辨率一样,显式指定的类型优先于隐式指定的类型,因此您的专业化(明确指定了int)优先于基础模板(隐式指定了int)。


Jerry,供您参考,我发布了一个问题,与您在此处提出的语句有关:“如果我们更改专业化,使其专业化为除基础模板提供的默认类型之外的类型,则选择基础模板”:https://stackoverflow.com/questions/52583833/role-of-default-template-arguments-in-the-context-of-partial-specialization - Fabio

0

当您编写Base<> base;时,编译器将尝试查找是否可能实例化Base<>类,如果可能,则代码将正常工作。 在这种情况下,由于基类的默认模板参数,它是可能的,因为编译器知道如果您编写Base<>,它需要创建Base<int,double>对象。即:因为:

template<class A = int, class B=double>
class Base
{};

所以代码运行良好。


问题是为什么它不应该失败?@Saksham - deeiip
它是否回答了问题? - Saksham
由于提供了默认参数,代码将正常工作。我认为这就是答案。 - deeiip
据我所知,这个答案的意思是不应该打印文本。 - chris
@chris 为什么?我的逻辑不成立了吗? - deeiip

0
template<class A = int, class B=double>
class Base
{};

这里分别将 A 和 B 的默认值/初始化声明为 int 和 double。

 template<class B>
 class Base <int, B>

在类定义中,第一个参数类似于一个常量值(这里是int;为什么要这样声明只会让事情变得复杂?最好删除第一个模板参数),而第二个模板参数是B,其默认值为“double”。

Base<> base;

当您创建类的对象时,尽管您没有指定模板参数,编译器会采用默认值(A和B),它们分别是'int'和'double',代码将不会出现任何错误或警告。
看看当您创建以下对象时会发生什么:
Base<float,char> b; 或者 Base<char,char> b;

1
我认为问题是:为什么在这种情况下选择部分特化而不是主模板。我没有看到你的答案中解决这个问题。 - Mat

0

简而言之:

template<class A = int, class B=double> class Base {}
  • 这行定义了主模板。主模板必须更为通用。在这种情况下,它接受任何类型的 A 和 B,即 Base<> base;
  • 同时,A = intB = double 是默认值,这意味着用没有模板参数实例化 Base<> base 实际上是 Base<int, double> base
  • 然后第一个参数 int 恰好匹配到部分特化模板 Base <int, B>,因此调用了 "it works" 函数。

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