SFINAE 表达式无法用 clang 编译

SFINAE expression fails to compile with clang

这看起来像是 clang 中的一个问题(我已经打开了一个错误 here),但我想确保我没有做错。

考虑以下代码:

#include <type_traits>
#include <cstddef>

template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };

template<std::size_t N>
struct S<N, N> { };

int main() {
    S<0, 1> c{};
}

编译失败,出现以下错误:

8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };

相同的代码使用以下行而不是 (1) 按预期工作:

template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>

SFINAE表达式几乎一样。它基于 std::enable_if_t 的专业化,我希望这两个示例的结果相同(成功或失败)。
我的期望错了吗?

请注意,GCC 在任何一种情况下都可以正常工作。

我认为这实际上是一个 gcc 错误,因为 [temp.class.spec]:

The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example:

template <class T, T t> struct C {};
template <class T> struct C<T, 1>;       // error

template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error

—end example ]

在您的示例中,第三个模板参数的类型取决于参数。当你把它换成 typename = std::enable_if_t<...> 时,这条规则就不再适用了。


注意:有什么理由在这里使用 SFINAE,而不是 static_assert-ing?