替换失败是依赖非类型模板参数的错误吗?

R. *_*des 10 c++ templates sfinae c++11 template-aliases

假设我有这些模板别名:

enum class enabler {};

template <typename T>
using EnableIf = typename std::enable_if<T::value, enabler>::type;
template <typename T>
using DisableIf = typename std::enable_if<!T::value, enabler>::type;
Run Code Online (Sandbox Code Playgroud)

我可以在GCC中执行以下操作:

#include <iostream>

template <typename T, EnableIf<std::is_polymorphic<T>> = {}>
void f(T) { std::cout << "is polymorphic\n"; }

template <typename T, DisableIf<std::is_polymorphic<T>> = {}>
void f(T) { std::cout << "is not polymorphic\n"; }

struct foo { virtual void g() {} };

int main() {
    f(foo {});
    f(int {});
}
Run Code Online (Sandbox Code Playgroud)

它打印:

多态性
不是多态的

这符合我的期望.

用clang代码不编译.它会生成以下错误消息.

test.cpp:11:58: error: expected expression
template <typename T, EnableIf<std::is_polymorphic<T>> = {}>
                                                         ^
test.cpp:14:59: error: expected expression
template <typename T, DisableIf<std::is_polymorphic<T>> = {}>
                                                          ^
test.cpp:20:3: error: no matching function for call to 'f'
  f(foo {});
  ^
test.cpp:12:6: note: candidate template ignored: couldn't infer template argument ''
void f(T) { std::cout << "is polymorphic\n"; }
     ^
test.cpp:15:6: note: candidate template ignored: couldn't infer template argument ''
void f(T) { std::cout << "is not polymorphic\n"; }
     ^
test.cpp:21:3: error: no matching function for call to 'f'
  f(int {});
  ^
test.cpp:12:6: note: candidate template ignored: couldn't infer template argument ''
void f(T) { std::cout << "is polymorphic\n"; }
     ^
test.cpp:15:6: note: candidate template ignored: couldn't infer template argument ''
void f(T) { std::cout << "is not polymorphic\n"; }
     ^
4 errors generated.
Run Code Online (Sandbox Code Playgroud)

它应该编译吗?哪两个编译器有问题?

Xeo*_*Xeo 7

首先,感谢@ 理查德史密斯#llvm IRC频道ontc上的解释.
不幸的是,这不是合法的C++,因此Clang是正确的:{}不是表达式而是braced-init-list,因此永远不会是非类型模板参数的初始化程序所需的常量表达式.

§14.3.2 [temp.arg.non-type] p1

模板参数的用于非类型,非模板模板参数应是以下之一:

  • 用于非类型模板参数整型或枚举类型,转换后的常量表达式的类型的(5.19)模板参数 ; 要么
  • [...]

一个解决方案是虚拟值enabler.

  • 这不是一个好的论据 - 我们不是在讨论模板参数(没有人试图例如.f <int,{}>`),而是默认参数,它们具有参数声明的语法,原则上可以在rhs上有`{}`(如果`enabler {}`是一个常量表达式,或者`x`,给定`enabler x {}`,常量应该没有问题).但是,8.3.6/3表示在模板参数声明的情况下应该有一个表达式. (2认同)