2016-08-16 33 views
6

C++标准14.8.2 $ 7说:替代在模板参数推演中如何工作?

取代在所有类型和表达了在函数类型并在模板参数声明使用发生。这些表达式不仅包括常量表达式,例如出现在数组边界或非类型模板参数中的常量表达式,还包括sizeof,decltype以及允许非常量表达式的其他上下文中的常规表达式(即非常量表达式)。替换按词汇顺序进行,并在遇到导致扣除失败的条件时停止。 [注意:异常规范中的等价替换只有在例外规范被实例化时才能完成,在这种情况下,如果替换导致无效类型或表达式,则程序不合格。 - 注完]

这里的标准提供了一个例子:

template <class T> struct A { using X = typename T::X; }; 
template <class T> typename T::X f(typename A<T>::X); 
template <class T> void f(...) { } 
template <class T> auto g(typename A<T>::X) -> typename T::X; 
template <class T> void g(...) { } 

void h() { 
    f<int>(0); // OK, substituting return type causes deduction to fail 
    g<int>(0); // error, substituting parameter type instantiates A<int> 
} 

为什么叫g<int>(0)是错误的吗?尾随返回类型T::X是否导致替换失败?模板功能fg之间有什么区别?

回答

4

其要点是,首先,

词汇顺序的取代前进并且当使扣失败的条件 遇到

其次,停止的A<int>的实例化定义会触发一个硬错误,而不是一个替代失败,因为这会导致在紧邻的上下文之外实例化一个格式不正确的构造typename T::X(与T == int)。 [temp.deduct]/8

只有无效的类型,并在 功能型的它的模板参数类型的直接背景和表达式可以导致 扣失败。 [:取代的类型和 表达式的评估可导致副作用,例如类模板特和/或功能模板 特,隐含定义的函数的生成等 这样的副作用的实例化 不在“紧急情况下”,并且可能导致程序不合格。 - 注完]

随着所讨论的模板,代入typename T::X在扣除失败函数类型结果(即,SFINAE);代入typename A<T>::X会导致严重错误。由于替换按照词汇顺序进行,因为template <class T> typename T::X f(typename A<T>::X);它首先替换为typename T::X,导致扣除失败,并且不会尝试进一步替换。另一方面,对于template <class T> auto g(typename A<T>::X) -> typename T::X;,首先替换为typename A<T>::X,这会导致严重错误。

+0

返回类型如何作为函数签名的一部分而不是参数? – Barry

+0

@Barry我认为返回类型和参数都被认为是函数签名的一部分 – Carousel

+0

@Barry它们都是函数模板签名的一部分,但我可能不应该在这里使用“签名”。 –