C++ 为什么这些模板模棱两可?
这本书在第275页有一个例子,我很难理解 引用书中的摘录C++ 为什么这些模板模棱两可?,c++,templates,C++,Templates,这本书在第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&
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;
};
模板
班级晋升{
公众:
典型结果;
};
模板
班级晋升{
公众:
typedef数组结果;
};
模板
班级晋升{
公众:
typedef数组结果;
};
不幸的是,部分专业化升级是无效的
既不比部分专业化更专业化,也不比部分专业化更专业化
促销
。为避免模板选择不明确,最后一部分
增加了专门化。它比以前的任何一种都更专业
两个部分专业
为什么前两个模板模棱两可,为什么最后一个模板解决了模棱两可的问题?当我尝试应用这些规则时,我要么不知道它是如何产生歧义的,要么如果我认为我有办法做到这一点,我不知道为什么最后一个模板可以解决这个问题。歧义是指同一个类可以从不同的专门化实例化,编译器不能支持一个专门化而不是另一个专门化,因为两者都不是更专业的。添加一个更专门的版本会使编译器选择该版本。这解决了模糊性,因为C++规则规定最专业化的模板应该在不太专业化的模板上选择。 这是因为在推导参数时,一个模板对于第一个参数更好,而另一个模板更好。
让我们看看
促销
两位候选人都可以匹配。在第一个参数上,Promotion
通过推断T=Array
进行匹配<代码>促销
通过推断T1=S来匹配。第二个是更好的匹配,因为Array
比T
更具体
在第二个参数上,Promotion
是完全匹配的<代码>升级
通过推断T2=S来匹配。由于数组
比数组
更匹配,因此第一个更具体
选择最佳模板的规则规定,与所有其他候选参数相比,一个参数必须更好地匹配,而所有其他参数不得更差。由于没有一位候选人符合这些标准,这是不明确的
第三个专门化确实满足标准(第一个参数与数组
一样好,第二个是完美的),因此它解决了歧义
如果你真的想让自己头晕目眩,试着阅读《标准》中的[temp.Decrete.partial]一节,其中所有这些规则都以良好的语言表述。在草案n3225中是14.8.2.4,其他版本中的编号可能会有所不同。也许您的困惑源于“比”更专业的关系如何运作。这是一个部分顺序,而不是全部顺序——这意味着给定两个模板专业化,并不总是一个比另一个更专业化
Anon的评论是正确的:假设第三专业化不存在,并且在代码的后面您有:
Promotion<Array<double>, Array<double> > foo;
这意味着:
Array<T1> = T
Array<T2> = T
意味着:
T = Array<T1>
T = Array<T2>
T=Array
T=阵列
因此答案也是否定的。给定任何类型的T1
,总是可以找到一个类型T
,这样T
与Array
的类型相同——只是字面上设置T=Array
。但一般来说,另一种类型T2
不受限制与T1
相同,如果不是(例如,如果T1=bool
但T2=float
),则不可能找到与Array
和Array
相同的类型T
。所以一般来说,不可能找到这样的类型T
在这种情况下,两个专业都不比另一个专业更专业,甚至都不如另一个专业。因此,如果需要实例化此模板类,并且两个专业化匹配(正如Anon给出的示例所示),则无法选择“最佳”一个。有问题,但作为一个具体示例,直接使用标准规则:
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
}
模板
类数组{};
模板
班级晋升{};
模板//a
班级晋升{
公众:
类型定义T结果;
};
模板//b
班级晋升{
公众:
typedef数组结果;
};
//模板
//班级晋升{
//公众:
//typedef数组结果;
// };
//---------------------------- §14.5.4.2/1:
模板
无效(促销);//A.
模板
无效b_(升级,Array);//B
//---------------------------- §14.5.5.2/3:
在{}上课;
类bT1{};
bT2类{};
无效a(促销);//A.
无效b(促销,Array);//B
无效测试()
{
//检查具体的“a”参数是否也适合“b”:
b(晋升,晋升);;
//失败,因此a至少不如b专业化
//检查具体的“b”参数是否也适合“a”:
a(促销,Array>());
//失败,因此b至少不像a那么专业化
}
免责声明:我不得不再次自学
我发这个是因为其他人™ 我觉得我的例子很有启发性,所以,可能对这里的读者也有帮助
干杯,从概念层面上看专业化做了什么
第一种说法是“如果T1和T2是相同的,我们就应该这样做。”
第二个是“如果T1和T2都是数组模板,我们就应该这样做”
好吧,那么。。。假设T1和T2都是相同的数组模板。我们应该用哪一个?没有什么好办法可以证明其中一个更适合这种情况
T = Array<T1>
T = Array<T2>
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
}