我在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
我的问题是编译器如何选择正确的一个?我需要在脑海中思考什么算法/方法/方法,以便了解将被称为哪一个算法
答案 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)至少存在一组与第一个参数匹配但与第二个参数不匹配的模板参数(例如,int
,int
,long
)。
所以:
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=A
和T1=A
。这是一致的。
进行<T1*,T1*>
时,事情会变得更加奇特。然后,如果您通过<A,A>
,它将尝试T1*=A
并失败;但是如果传递了<A*,A*>
,它将以T1*=A*
开头,然后剥离*
并得到T1=A
,然后再次对第二个参数执行该操作。
非推论上下文是不同的。当您使用非推导上下文时,例如std::enable_if_t<some_bool, T1>
,则不会对该参数进行模式匹配。取而代之的是,将其他参数进行模式匹配,然后替换专业化模板变量。否则失败。
最后一位正在排序。如果两个二级专业通过,那么严格地以“更专业”为准。如果两者都不是严格意义上的专业,那么两者都不会赢。更专业的规则很复杂;直观的想法是,如果一个专业能够始终匹配另一个人的情况,而反之则不然,那么匹配程度越低的人就越专业。