首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这些模板模棱两可?

为什么这些模板模棱两可?
EN

Stack Overflow用户
提问于 2010-12-14 01:37:22
回答 5查看 2K关注 0票数 7

书中的C++模板:完整指南有一个例子,在第275页,我有困难的包装我的头。

引用这本书的摘录..。

代码语言:javascript
复制
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>更专业化。为了避免模板选择的模糊性,添加了最后的部分专门化。它比前两种局部专门化中的任何一种都更专业化。

为什么前两个模板是模棱两可的,为什么最后一个模板要解决歧义问题?当我试图应用这些规则时,我要么不知道它是如何产生歧义的,要么就是我认为我有办法做到这一点,我不知道最后一个模板为什么解决了这个问题。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-12-14 03:33:38

也许你的困惑来自于这种关系是如何“比”更专业化的。这是一个局部的顺序,而不是一个完全的顺序--这意味着给定两个模板的专门化,并不总是这样,一个比另一个更专业化。

Anon的评论是正确的:假设第三次专门化不存在,那么在您的代码后面,您有:

代码语言:javascript
复制
Promotion<Array<double>, Array<double> > foo;

(当然,您可能不会实际创建这个空结构类型的变量,但这只是强制实例化的最简单方法。)

鉴于foo的这一声明,第一批2项专门化中的哪一项将被选中?

  • 专业1适用于T = Array<double>
  • 专业2适用,与T1 = doubleT2 = double

这两种专业都是适用的,所以我们需要确定哪一种比另一种更专业,并选择这一种。多么?我们会说,如果X至少和Y一样专业,那么它比Y更专业化,但Y至少没有X那么专业。虽然这似乎只是为了解决这个问题,但我们可以用一个聪明的规则来回答这个新问题:

X 至少与 Y 一样专业,如果不管我们为 X**,的模板参数指定了哪些类型,最终的类型总是可以由** Y**.**匹配的话

请注意,我们忘记了当前实例化所涉及的特定类型(在本例中是double) --“至少与”关系是部分特定化本身的属性,而不依赖于特定的实例化。

专业化1总能与专业化2相匹配吗?这个过程有点像代数。对于任何类型的T,我们都需要找到T1T2类型,以便:

代码语言:javascript
复制
Promotion<Array<T1>, Array<T2> > = Promotion<T, T>

这意味着:

代码语言:javascript
复制
Array<T1> = T
Array<T2> = T

所以答案是否定的。考虑到第一个隐含的结果(给定任何类型的T ),通常不可能找到T1类型,使Array<T1>T的类型相同。(如果T碰巧是Array<long>,但如果Tintchar*或大多数其他类型,则会起作用。)

那另一个方向呢?专业化2总能与专业化1相匹配吗?对于任何类型的T1T2,我们都需要找到一个类型T,以便:

代码语言:javascript
复制
Promotion<T, T> = Promotion<Array<T1>, Array<T2> >

暗示:

代码语言:javascript
复制
T = Array<T1>
T = Array<T2>

所以答案再次是否定的。给定任何类型的T1,总是有可能找到一个类型T,使得TArray<T1>是相同的类型--只是字面上设置了T = Array<T1>。但通常情况下,其他类型的T2不一定与T1相同,如果不是(例如,如果是T1 = bool,而是T2 = float),那么就不可能找到与Array<T1>Array<T2>相同的类型T。因此,一般来说,不可能找到这样的类型T

在这种情况下,不仅专业化程度既不高于其他专业,也不像其他专业一样专业化。因此,如果需要实例化这个模板类,并且这两个专门化匹配--就像Anon给出的示例中所做的那样--就没有办法选择“最佳”类。

票数 15
EN

Stack Overflow用户

发布于 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,其他版本的编号可能有所不同。

票数 3
EN

Stack Overflow用户

发布于 2010-12-14 03:49:31

黑客有一个已应答问题,但作为一个具体的例子,只是直接使用标准的规则:

代码语言:javascript
复制
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
}    

免责声明:我不得不再教自己一次。

我之所以发布这篇文章,是因为其他人的™发现我的例子很有启发性,因此,可能也会帮助这里的读者。

干杯.

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4435159

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档