Consider the following program:
template <class T> struct A { using X = typename T::X; };
template <class T, typename A<T>::X* = nullptr> void f(T, int);
void f(...);
template <class T> void g(T, int, typename A<T>::X* = nullptr); // #
void g(...);
int main() {
// f(0, nullptr); // error
g(0, nullptr); // ok
}
g(0, nullptr)
compiles while f(0, nullptr)
does not (tested under GCC trunk and Clang trunk on Godbolt). It seems that during the template argument deduction process of #
, the compiler does not instantiate A<int>
when it finds the argument nullptr
does not match the parameter int
. Where does the standard specify this behavior?
This is CWG1391:
If deduction succeeds for all parameters that contain
template-parameters that participate in template argument deduction, and all template arguments are explicitly specified, deduced, or
obtained from default template arguments, remaining parameters are
then compared with the corresponding arguments. For each remaining
parameter P
with a type that was non-dependent before substitution
of any explicitly-specified template arguments, if the corresponding
argument A
cannot be implicitly converted to P
, deduction fails.
It is possible that you are bitten by DR #1844. In [temp.deduct]/8 it states:
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [ Note: If no diagnostic is required, the program is still ill-formed.
Access checking is done as part of the substitution process. — end note] Only invalid types and expressions in the immediate context of the function type, its template parameter types, and its explicit-specifier can result in a deduction failure. [ Note: The substitution into types and expressions can result in effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]
The problem here is that "immediate context" is not really given a definition, leading to variance among compilers.