确定每次使用哪种模板专业化结构

时间:2019-07-04 20:11:53

标签: c++ templates template-specialization

我在C++中有以下声明:

template<class T1, class T2> struct canAssign {
    enum { result = false };
};
template<class T1> struct canAssign<T1,T1> {
    enum { result = true };
};

我有以下通话(A扩展了B):

canAssign<A,A>::result;
canAssign<B,A>::result;
canAssign<B*,A*>::result;

我知道它使用了template specialization功能,但是我似乎不明白它是如何决定每次选择哪个功能的?

编辑:我知道输出应该是什么:

true
false
false

我的问题是编译器如何选择正确的一个?我需要在脑海中思考什么算法/方法/方法,以便了解将被称为哪一个算法

4 个答案:

答案 0 :(得分:0)

可能的继承不在此处计算。

所以你有

canAssign<A, A>::result;   // true  T1=A, T2=A as T1=T2, use specialization
canAssign<B, A>::result;   // false T1=B, T2=A
canAssign<B*, A*>::result; // false T1=B*, T2=A*

答案 1 :(得分:0)

  

我的问题是编译器如何选择正确的一个?我需要在脑海中思考什么算法/方法/方法,以便了解将被称为哪一个算法

该算法在您要定位的特定标准的[temp.class.spec.match]部分(及相关标准)中进行了描述。

答案 2 :(得分:0)

  

我的问题是编译器如何选择正确的一个?我需要在脑海中思考什么算法/方法/方法,以便了解将被称为哪一个算法

编译器选择可用的最特殊的版本(如果不确定选择可用的最特殊的版本,则会出现错误。

一个版本比另一个版本更专业化

1)模板参数的所有匹配,对于更专业的匹配,对于不那么专业的匹配

2),并且针对专业程度较低的匹配项与针对专业程度较低的匹配项

在您的情况下,您有两个canAssign版本:主要版本和专业版本。

很明显,专业化比主要版本要专业化,

canAssign<A,A>::result;

机器人版本匹配,因此编译器选择专业化版本。

在其他情况下

canAssign<B,A>::result;
canAssign<B*,A*>::result;

仅主版本匹配,因此编译器选择主版本。

另一个可以更好地说明这一点的示例:假设您有一个模板foo,其中有两个专业化知识

template <typename, typename, typename>
struct foo 
 { };

template <typename A, typename B>
struct foo<A, A, B>
 { };

template <typename A>
struct foo<A, A, A>
 { };

第二个专业比第一个更加专业。

事实上

1)匹配第二个模板的所有模板参数集(必须全部相等)也必须匹配第一个(第一个和第二个相等)

2)至少存在一组与第一个参数匹配但与第二个参数不匹配的模板参数(例如,intintlong)。

所以:

1)第二个专业比第一个专业更

2)第一个专业化版本比主版本更专业化

所以

  • foo<int, int, int>匹配所有版本,因此编译器选择第二个特殊化

  • foo<int, int, long>匹配主版本和第一个专业化版本,因此编译器选择第一个专业化版本

  • foo<int, long, int>仅匹配主要版本,因此编译器选择主要版本。

答案 3 :(得分:0)

这是一种模式匹配。

这将是一个简单的故事。它不完全符合标准,但我发现它产生了很好的影响力。

template<class T1, class T2> struct canAssign {
  enum { result = false };
};

这是主要规范。它定义了模板签名-由<class T1, class T2>定义的两个类。如果没有其他匹配项,它也会被实例化。

template<class T1> struct canAssign<T1,T1> {
  enum { result = true };
};

这是第二专业。 <class T1>在这里有不同的用途;它引入了与模式匹配的变量,而不是参数。

参数在<T1,T1>部分中。编译器将<T1,T1>与传递的参数进行匹配。

“推论上下文”中的任何参数都是独立匹配的。因此,如果您通过<A,B>,则它匹配T1=A,然后匹配T1=B。这是不一致的;专业不匹配。如果您通过<A,A>,它将匹配T1=AT1=A。这是一致的。

进行<T1*,T1*>时,事情会变得更加奇特。然后,如果您通过<A,A>,它将尝试T1*=A并失败;但是如果传递了<A*,A*>,它将以T1*=A*开头,然后剥离*并得到T1=A,然后再次对第二个参数执行该操作。

非推论上下文是不同的。当您使用非推导上下文时,例如std::enable_if_t<some_bool, T1>,则不会对该参数进行模式匹配。取而代之的是,将其他参数进行模式匹配,然后替换专业化模板变量。否则失败。

最后一位正在排序。如果两个二级专业通过,那么严格地以“更专业”为准。如果两者都不是严格意义上的专业,那么两者都不会赢。更专业的规则很复杂;直观的想法是,如果一个专业能够始终匹配另一个人的情况,而反之则不然,那么匹配程度越低的人就越专业。