I have the following piece of code:
template <typename, typename>
struct AAA{};
template<typename ...Args>
void f(AAA<Args...> *) {}
int main() {
f<int, int>(nullptr);
}
This code results in a compile error. When compiling using g++ -std=c++1z
the error shows as follows:
prog.cc: In function 'int main()':
prog.cc:8:24: error: no matching function for call to 'f<int, int>(std::nullptr_t)'
f<int, int>(nullptr);
^
prog.cc:5:6: note: candidate: template<class ... Args> void f(AAA<Args ...>*)
void f(AAA<Args...> *) {}
^
prog.cc:5:6: note: template argument deduction/substitution failed:
prog.cc:8:24: note: mismatched types 'AAA<Args ...>*' and 'std::nullptr_t'
f<int, int>(nullptr);
Using clang++ -std=c++1z
the error is:
prog.cc:8:5: error: no matching function for call to 'f'
f<int, int>(nullptr);
^~~~~~~~~~~
prog.cc:5:6: note: candidate template ignored: could not match 'AAA<int, int, Args...> *' against 'nullptr_t'
void f(AAA<Args...> *) {}
^
1 error generated.
I am running those above in a MSYS2 MinGW-w64 environment. My GCC version is GCC 7.1.0 and my Clang version is 4.0.0; the standard library I use both in GCC and in Clang is the libstdc++ bundled with my GCC compiler.
In my opinion, the call to function template foo
has its template parameter explicitly specified thus the template parameter pack and the function argument type should already be specified. However, the error diagnostics shown above seem to suggest that the exact type of function parameter and the nullptr
argument does not match, which seems to be a issue only possible when function argument deduction occurs. So my question is, why does such error occur? Is it just a compiler bug, or does the C++ standard have some rules that indicate the original code is just ill-formed?
You may think the compiler should deduce the pack as int ,int
, but the C++ standard explicitly requires the behavior you observed.
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments. [ Example:
template<class ... Types> void f(Types ... values); void g() { f<int*, float*>(0, 0, 0); // Types is deduced to the sequence int*, float*, int }
— end example ]
The above means that even though some of the parameters were specified, deduction doesn't end. The parameter pack must always be expandable by argument deduction. It's as if the explicit arguments that were given are an instantiation of a template with a trailing parameter pack. When coupled with the following:
Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. ...
The compiler must match the un-deduced arguments to an empty pack. But it has nothing to deduce it from.
As such, your attempt to plug Args...
into AAA
cannot possibly match. Because the type sequence is two types with a trailing list (that the compiler cannot deduce as empty from nullptr
). While AAA
expects just two types.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments