https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90971
--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> --- #include <type_traits> template<typename T> struct is_foo : std::false_type { }; template<typename T> constexpr bool is_foo_v = is_foo<T>::value; template<typename T, typename = typename std::enable_if<is_foo<T>::value>::type> void bar1(T) { } template<typename T, typename = std::enable_if_t<is_foo<T>::value>> void bar2(T) { } template<typename T, typename = std::enable_if_t<is_foo_v<T>>> void bar3(T) { } int main() { bar1(1); bar2(1); bar3(1); } GCC prints: enab.cc: In function 'int main()': enab.cc:17:9: error: no matching function for call to 'bar1(int)' 17 | bar1(1); | ^ enab.cc:7:6: note: candidate: 'template<class T, class> void bar1(T)' 7 | void bar1(T) { } | ^~~~ enab.cc:7:6: note: template argument deduction/substitution failed: enab.cc:6:22: error: no type named 'type' in 'struct std::enable_if<false, void>' 6 | template<typename T, typename = typename std::enable_if<is_foo<T>::value>::type> | ^~~~~~~~ enab.cc:18:9: error: no matching function for call to 'bar2(int)' 18 | bar2(1); | ^ enab.cc:10:6: note: candidate: 'template<class T, class> void bar2(T)' 10 | void bar2(T) { } | ^~~~ enab.cc:10:6: note: template argument deduction/substitution failed: In file included from enab.cc:1: /home/jwakely/gcc/10/include/c++/10.0.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = void]': enab.cc:9:22: required from here /home/jwakely/gcc/10/include/c++/10.0.0/type_traits:2553:11: error: no type named 'type' in 'struct std::enable_if<false, void>' 2553 | using enable_if_t = typename enable_if<_Cond, _Tp>::type; | ^~~~~~~~~~~ enab.cc:19:9: error: no matching function for call to 'bar3(int)' 19 | bar3(1); | ^ enab.cc:13:6: note: candidate: 'template<class T, class> void bar3(T)' 13 | void bar3(T) { } | ^~~~ enab.cc:13:6: note: template argument deduction/substitution failed: It would be better if the first and second errors both showed the location as the default template argument in the function template's template-head. Currently the first one shows the 'typename' before it: enab.cc:7:6: note: template argument deduction/substitution failed: enab.cc:6:22: error: no type named 'type' in 'struct std::enable_if<false, void>' 6 | template<typename T, typename = typename std::enable_if<is_foo<T>::value>::type> | ^~~~~~~~ And the second one shows the failure as being inside the enable_if_t alias: enab.cc:10:6: note: template argument deduction/substitution failed: In file included from enab.cc:1: /home/jwakely/gcc/10/include/c++/10.0.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = void]': enab.cc:9:22: required from here /home/jwakely/gcc/10/include/c++/10.0.0/type_traits:2553:11: error: no type named 'type' in 'struct std::enable_if<false, void>' 2553 | using enable_if_t = typename enable_if<_Cond, _Tp>::type; | ^~~~~~~~~~~ I think I'd prefer if both of these were special cased for std::enable_if and std::enable_if_t and showed the location as the argument to it: enab.cc:7:6: note: template argument deduction/substitution failed: enab.cc:6:22: error: enable_if condition not satisfied 'is_foo<T>::value' 6 | template<typename T, typename = typename std::enable_if<is_foo<T>::value>::type> | ^~~~~~~~~~~~~~~~ The third error is especially bad, as no reason is given at all: enab.cc:13:6: note: template argument deduction/substitution failed: Clang prints almost the same thing for all three cases: enab.cc:17:3: error: no matching function for call to 'bar1' bar1(1); ^~~~ enab.cc:7:6: note: candidate template ignored: requirement 'is_foo<int>::value' was not satisfied [with T = int] void bar1(T) { } ^ enab.cc:18:3: error: no matching function for call to 'bar2' bar2(1); ^~~~ enab.cc:10:6: note: candidate template ignored: requirement 'is_foo<int>::value' was not satisfied [with T = int] void bar2(T) { } ^ enab.cc:19:3: error: no matching function for call to 'bar3' bar3(1); ^~~~ enab.cc:13:6: note: candidate template ignored: requirement 'is_foo_v<int>' was not satisfied [with T = int] void bar3(T) { } ^ 3 errors generated.