更明确地说,编译器是否应该将true_type
值视为enable_if
的第一个参数中的true
值,因为true_type
确实std::integral_constant<bool, true>
,并且integral_constant
operator value_type
定义了类型转换函数?
以下是最简单的测试代码:
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_pod<T>{}>
test(T)
{
}
int main()
{
test(true);
}
它被GCC和Clang接受,但被MSVC拒绝(直到Visual Studio 2019 v16.3.1(。
您的代码格式正确,对于非类型模板参数,应考虑转换后的常量表达式。
可与非类型模板参数一起使用的模板参数可以是模板参数类型的任何转换常量表达式。
类型为
T
的转换常量表达式是表达式 隐式转换为类型T
,其中转换后的表达式为 常量表达式,隐式转换序列包含 只:
constexpr
用户定义的转换(因此可以在需要整型的情况下使用类(
从std::integral_constant
继承std::is_pod
的转换运算符constexpr
用户定义的转换,然后从std::is_pod
转换的bool
是转换后的常量表达式,可以应用。
作为解决方法(我想您已经意识到(,您可以使用std::is_pod_v<T>
(自 C++17 起(或std::is_pod_v<T>::value
。
要回答更一般的问题,是的,它应该被接受。MSVC 默认为 C++14,因此我将基于该标准给出答案。
[temp.arg.nontype]
1 非类型、非模板模板参数的模板参数 应为以下之一:
1.1 - 对于整型或枚举的非类型模板参数 type,一个转换后的常量表达式 ([expr.const](,其类型为 模板参数;或
[EXPR.const]
3 积分常量表达式是积分或 无作用域枚举类型,隐式转换为 PR值,其中 转换后的表达式是核心常量表达式。一 转换 类型 T 的常量表达式是隐式转换的表达式 转换为类型 T 的 prvalue,其中转换后的表达式是核心 常量表达式和隐式转换序列仅包含 用户定义的转换,左值到右值的转换([conv.lval](, 整体促销([会议舞会](和积分转换 ([conv.integral](,而不是缩小转换范围([dcl.init.list](。
由于integral_constant
支持constexpr operator T()
并且此用户定义的转换可能出现在转换后的常量表达式中,因此您的代码完全有效。MSVC似乎挂断的是它的解析。因为当我尝试你的例子时,它吐出了这个
<source>(4): error C2059: syntax error: '<end Parse>' <source>(4): error C2143: syntax error: missing ';' before '{' <source>(4): error C2143: syntax error: missing '>' before ';' <source>(4): error C2988: unrecognizable template declaration/definition <source>(4): error C2059: syntax error: ';' <source>(4): error C2447: '{': missing function header (old-style formal list?) <source>(4): error C2988: unrecognizable template declaration/definition <source>(4): error C2059: syntax error: '>' <source>(6): error C2143: syntax error: missing ';' before '{' <source>(6): error C2447: '{': missing function header (old-style formal list?) <source>(11): error C3861: 'test': identifier not found
Microsoft对模板的处理在历史上与GCC或Clang不同,这可以解释解析中的这个问题。