隐式类型转换在模板参数的上下文中是否起作用?

3
更明确地说,编译器在处理 enable_if 函数的第一个参数时,是否应该将 true_type 值视为 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)所拒绝。


std::enable_if_t<(std::is_pod<T>{})> 可以工作。 - Evg
2个回答

5

你的代码格式良好,应该考虑使用转换后的常量表达式作为非类型模板参数

可以与非类型模板参数一起使用的模板参数可以是任何转换后的常量表达式,其类型与模板参数的类型相同。

类型为T转换后的常量表达式是一个被隐式转换为类型T的表达式,其中转换后的表达式是一个常量表达式,并且隐式转换序列仅包含:

  • constexpr用户定义的转换(因此可以在需要整数类型的地方使用类)

std::is_pod的转换运算符是从std::integral_constant继承的,它是constexpr用户定义的转换,然后从std::is_pod转换的bool是转换常量表达式并可应用。


作为一种解决方法(我想你已经意识到了),您可以使用std::is_pod_v<T>(自C++17以来)或std::is_pod_v<T> ::value

谢谢,我知道解决方法。我只是想知道这是否是MSVC的一个bug。 - Yongwei Wu
@YongweiWu 我认为是的,特别是当gcc和clang都表示是的时。 - songyuanyao

3
回答更一般的问题,是的,应该被接受。MSVC默认使用C++14,因此我将以这个标准为基础回答。

[temp.arg.nontype]

非类型、非模板模板参数的模板实参应为以下之一:

1.1 - 对于整型或枚举类型的非类型模板参数,是一个转换后的常量表达式 ([expr.const]),其类型与模板参数的类型相同;或

[expr.const]

3 整数常量表达式是指具有整数或无作用域枚举类型的表达式,被隐式转换为prvalue类型,其中被转换表达式是一个核心常量表达式。类型为T的转换常量表达式是指一个被隐式转换为类型T的prvalue表达式,并且被转换表达式是一个核心常量表达式,并且隐式转换序列仅包含用户定义的转换、左值到右值的转换([conv.lval])、整数提升([conv.prom])和整数转换([conv.integral]),但不包括缩窄转换([dcl.init.list])。

由于integral_constant支持constexpr operator T(),并且这种用户定义的转换可能出现在转换常量表达式中,因此您的代码是完全有效的。但是,MSVC似乎卡在了解析上。当我尝试您的示例时,它会输出this out

<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
微软对模板的处理方法与GCC或Clang有所不同,这可能导致解析问题。

我想我忘了提到,但我确实在命令行上指定了 cl /EHsc /std:c++17 test.cpp - Yongwei Wu
1
@YongweiWu - 没有太大的区别。C++17增加了更多可能的常量表达式。因此,在C++14中有效的内容在C++17中仍然是有效的常量表达式。 - StoryTeller - Unslander Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接