The following snippet is rejected by Clang on C++17, accepted by GCC on C++17 and rejected by GCC on C++14. This is consistent with all recent compiler versions. What's the correct behavior ?
template <class T, class = int>
struct test1 {};
template <class T, template <class> class>
struct test2 {};
using test_t = test2<int, test1>;
EDIT: Apparently this is actually implemented on Clang, it just needs an explicit flag: -frelaxed-template-template-args
which is not included when using -pedantic
.
GCC's is the correct behavior. It is consistent with p0522r0, which was accepted into C++17.
From the paper's introduction:
Template template-parameters only bind to arguments with matching parameter lists. Matching is currently defined as an exact match; each template parameter in the argument's parameter list must have the same kind and type as the corresponding parameter in the template-parameter's parameter list. (There is an ill-advised exception to this rule when a parameter pack appears in the template-parameter's parameter list; this paper preserves that special behavior.) The matching rules exclude many reasonable arguments. This paper adjusts the matching rules to invoke partial ordering to determine when a template template-argument is a valid match for a template-parameter.
The paper also contains code examples of what will change, and this snippet is very much like the example whose behavior you observed:
template <template <typename> class> void FD();
template <typename, typename = int> struct SD { /* ... */ };
FD<SD>(); // OK; error before this paper (CWG 150)