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

时间:2012-04-16 19:41:49

标签: c++ templates c++11 sfinae 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;

我可以在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 {});
}

打印:

  

是多态的   不是多态的

符合我的期望。

使用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.

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

1 个答案:

答案 0 :(得分:7)

首先,感谢Richard Smith#llvm IRC Channel on oftc的解释。
不幸的是,这不是合法的C ++,因此Clang是正确的:{}不是表达式而是 braced-init-list ,因此永远不会是常量表达式,在非类型模板参数的初始化程序中需要。

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

  

非类型非模板模板参数 template-argument 应为以下之一:

     
      
  • 对于整数或枚举类型的非类型模板参数 template-parameter <的类型的转换常量表达式(5.19) / em>的;或
  •   
  • [...]
  •   

一个解决方案是enabler中的虚拟值。