Carousel - 5 months ago 24

C++ Question

C++ standard 14.8.2$7 says that:

The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside,`sizeof`

, and other contexts that allow non-constant expressions. The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered. [ Note: The equivalent substitution in exception specifications is done only when the exception-specification is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or expression. — end note ]`decltype`

The standard provides an example here:

`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>

}

Why calling

`g<int>(0)`

`T::X`

`f`

`g`

Answer

The key points are, first,

The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered

And second, instantiation of `A<int>`

's definition triggers a hard error, not a substitution failure, because that results in instantiating an ill-formed construct `typename T::X`

(with `T == int`

) outside the immediate context. [temp.deduct]/8:

Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [

Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. —end note]

With the templates at issue, substituting into `typename T::X`

in the function signature results in a deduction failure (i.e., SFINAE); substituting into `typename A<T>::X`

results in a hard error. Since substitution proceeds in lexical order, for `template <class T> typename T::X f(typename A<T>::X);`

it substitutes into `typename T::X`

first, resulting in a deduction failure, and further substitution is not attempted. For `template <class T> auto g(typename A<T>::X) -> typename T::X;`

, on the other hand, it substitutes into `typename A<T>::X`

first, which results in a hard error.