Description
Bugzilla Link | 17917 |
Version | trunk |
OS | Linux |
CC | @DougGregor |
Extended Description
Consider:
template<bool> struct enable_if { typedef void type; };
template <class T> class Foo {};
template <class X> constexpr bool check() { return true; }
template <class X, class Enable = void> struct Bar {};
#ifdef FUNCTION_ORDERING
template<class X> void func(Bar<X, typename enable_if<check<X>()>::type>) { }
template<class T> int func(Bar<Foo<T>>) { return 0; }
int (*p)(Bar<Foo<int>>) = func;
#else
template<typename X> struct Bar<X, typename enable_if<check<X>()>::type> {};
template<typename X> struct Bar<Foo<X>> { typedef int type; };
Bar<Foo<int>>::type bar;
#endif
Per 14.5.5.2/1, the class template partial specialization partial ordering and the function template partial ordering above should behave exactly the same. But they don't: for clang, gcc, and edg, the FUNCTION_ORDERING
case is accepted and the other (class ordering) case is rejected.
Morally, both cases should be rejected; this is ambiguous because the first template has the constraint that enable_if<check<X>()>::type == void
, and the second template has the constraint that X == Foo<T>
for some T
. Clearly, neither of these implies the other.
Practically, we're missing a call to something like FinishTemplateArgumentDeduction
in the FunctionTemplateDecl
form of isAtLeastAsSpecializedAs
: we fail to check that the deduction produces template arguments that make the deduced A
compatible with the original A
(as required by [temp.deduct.type]p1).