替换如何在模板参数推导中起作用?

Car*_*sel 6 c++ substitution

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>
}
Run Code Online (Sandbox Code Playgroud)

为什么打电话g<int>(0)是错误的?trailing-return-type不会T::X导致替换失败?模板功能fg?有什么区别?

T.C*_*.C. 4

关键点是,首先,

\n\n
\n

替换按词法顺序进行,并在遇到导致推导失败的条件时停止\n

\n
\n\n

其次, \ 定义的实例化会触发硬错误,而不是替换失败,因为这会导致在直接上下文之外A<int>实例化格式不正确的构造typename T::X(带有)。[温度扣除]/8 :T == int

\n\n
\n

只有函数类型及其模板参数类型的直接上下文中的无效类型和表达式才可能导致推导失败。[注意:替换类型和表达式的求值可能会导致副作用,例如类模板特化和/或函数模板特化的实例化、隐式定义函数的生成等。副作用不在\xe2\x80\x9c 直接上下文\xe2\x80\x9d 中,并且可能导致\n 程序格式错误。\xe2\x80\x94尾注]

\n
\n\n

对于有问题的模板,typename T::X在函数类型中替换到会导致推导失败(即SFINAE);代入会typename A<T>::X导致硬错误。由于替换是按照词汇顺序进行的,因此 fortemplate <class T> typename T::X f(typename A<T>::X);替换为typename T::Xfirst,导致演绎失败,并且不会尝试进一步替换。template <class T> auto g(typename A<T>::X) -> typename T::X;另一方面,对于 ,它替换为first typename A<T>::X,这会导致硬错误。

\n