书中的C++模板:完整指南有一个例子,在第275页,我有困难的包装我的头。
引用这本书的摘录..。
template <typename T>
class Promotion<T,T> {
public:
typdef T ResultT;
};
template<typename T1, typename T2>
class Promotion<Array<T1>, Array<T2> > {
public:
typedef Array<typename Promotion<T1,T2>::ResultT> ResultT;
};
template<typename T>
class Promotion<Array<T>, Array<T> > {
public:
typedef Array<typename Promotion<T,T>::ResultT> ResultT;
};不幸的是,部分专门化
Promotion<Array<T1>, Array<T2> >并不比部分专门化Promotion<T,T>更专业化。为了避免模板选择的模糊性,添加了最后的部分专门化。它比前两种局部专门化中的任何一种都更专业化。
为什么前两个模板是模棱两可的,为什么最后一个模板要解决歧义问题?当我试图应用这些规则时,我要么不知道它是如何产生歧义的,要么就是我认为我有办法做到这一点,我不知道最后一个模板为什么解决了这个问题。
发布于 2010-12-14 03:33:38
也许你的困惑来自于这种关系是如何“比”更专业化的。这是一个局部的顺序,而不是一个完全的顺序--这意味着给定两个模板的专门化,并不总是这样,一个比另一个更专业化。
Anon的评论是正确的:假设第三次专门化不存在,那么在您的代码后面,您有:
Promotion<Array<double>, Array<double> > foo;(当然,您可能不会实际创建这个空结构类型的变量,但这只是强制实例化的最简单方法。)
鉴于foo的这一声明,第一批2项专门化中的哪一项将被选中?
T = Array<double>。T1 = double,T2 = double。这两种专业都是适用的,所以我们需要确定哪一种比另一种更专业,并选择这一种。多么?我们会说,如果X至少和Y一样专业,那么它比Y更专业化,但Y至少没有X那么专业。虽然这似乎只是为了解决这个问题,但我们可以用一个聪明的规则来回答这个新问题:
X 至少与 Y 一样专业,如果不管我们为 X**,的模板参数指定了哪些类型,最终的类型总是可以由** Y**.**匹配的话
请注意,我们忘记了当前实例化所涉及的特定类型(在本例中是double) --“至少与”关系是部分特定化本身的属性,而不依赖于特定的实例化。
专业化1总能与专业化2相匹配吗?这个过程有点像代数。对于任何类型的T,我们都需要找到T1和T2类型,以便:
Promotion<Array<T1>, Array<T2> > = Promotion<T, T>这意味着:
Array<T1> = T
Array<T2> = T所以答案是否定的。考虑到第一个隐含的结果(给定任何类型的T ),通常不可能找到T1类型,使Array<T1>与T的类型相同。(如果T碰巧是Array<long>,但如果T是int、char*或大多数其他类型,则会起作用。)
那另一个方向呢?专业化2总能与专业化1相匹配吗?对于任何类型的T1和T2,我们都需要找到一个类型T,以便:
Promotion<T, T> = Promotion<Array<T1>, Array<T2> >暗示:
T = Array<T1>
T = Array<T2>所以答案再次是否定的。给定任何类型的T1,总是有可能找到一个类型T,使得T与Array<T1>是相同的类型--只是字面上设置了T = Array<T1>。但通常情况下,其他类型的T2不一定与T1相同,如果不是(例如,如果是T1 = bool,而是T2 = float),那么就不可能找到与Array<T1>和Array<T2>相同的类型T。因此,一般来说,不可能找到这样的类型T。
在这种情况下,不仅专业化程度既不高于其他专业,也不像其他专业一样专业化。因此,如果需要实例化这个模板类,并且这两个专门化匹配--就像Anon给出的示例中所做的那样--就没有办法选择“最佳”类。
发布于 2010-12-14 03:24:23
这是因为在推导参数时,一个模板对第一个参数更好,而另一个对第二个参数更好。
让我们看看Promotion< Array<S>, Array<S> >。
两位候选人都可以匹配。在第一个参数上,Promotion< T, T >通过推导T = Array<S>来匹配。Promotion< T1, T2 >通过推导T1 = S来匹配。第二个是更好的匹配,因为Array<T1>比T更具体。
在第二个参数上,Promotion< T = Array<S>, T = Array<S> >是完全匹配的。Promotion< T1 = S, T2 >通过推导T2 = S来匹配。因为Array<S>比Array<T2>更匹配,所以第一个更具体。
选择最佳模板的规则规定,与所有其他候选参数相比,一个参数必须更好地匹配,而所有其他参数都不差。由于没有候选人符合这些标准,这是模棱两可的。
第三个专门化符合标准(第一个参数和Array<T1>一样好,第二个是完美的),因此它解决了歧义问题。
如果你真的想让自己头晕目眩,试着阅读标准中的temp.deduct.partial部分,其中所有的规则都是用好的律师说明的。在n3225草案中是14.8.2.4,其他版本的编号可能有所不同。
发布于 2010-12-14 03:49:31
黑客有一个已应答问题,但作为一个具体的例子,只是直接使用标准的规则:
template< class T >
class Array {};
template< class T1, class T2 >
class Promotion {};
template <typename T> // a
class Promotion<T,T> {
public:
typedef T ResultT;
};
template<typename T1, typename T2> // b
class Promotion<Array<T1>, Array<T2> > {
public:
typedef Array<typename Promotion<T1,T2>::ResultT> ResultT;
};
// template<typename T>
// class Promotion<Array<T>, Array<T> > {
// public:
// typedef Array<typename Promotion<T,T>::ResultT> ResultT;
// };
//---------------------------- §14.5.4.2/1:
template< class T >
void a_( Promotion< T, T > ); // a
template< class T1, class T2 >
void b_( Promotion< Array< T1 >, Array< T2 > > ); // b
//---------------------------- §14.5.5.2/3:
class aT {};
class bT1 {};
class bT2 {};
void a( Promotion< aT, aT > ); // a
void b( Promotion< Array< bT1 >, Array< bT2 > > ); // b
void test()
{
// Check if the concrete 'a' arguments fit also 'b':
b_( Promotion< aT, aT >() );
// Fails, so a is not at least as specialized as b
// Check if the concrete 'b' arguments fit also 'a':
a_( Promotion< Array< bT1 >, Array< bT2 > >() );
// Fails, so b is not at least as specialized as a
} 免责声明:我不得不再教自己一次。
我之所以发布这篇文章,是因为其他人的™发现我的例子很有启发性,因此,可能也会帮助这里的读者。
干杯.
https://stackoverflow.com/questions/4435159
复制相似问题