隐式转换应该在模板参数的上下文中工作吗?

Should implicit conversion work in the context of a template argument?

更明确地说,编译器是否应该在 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)。

您的代码格式正确,converted constant expression should be considered for non-type template parameter

The template argument that can be used with a non-type template parameter can be any converted constant expression of the type of the template parameter.

A converted constant expression of type T is an expression implicitly converted to type T, where the converted expression is a constant expression, and the implicit conversion sequence contains only:

  • constexpr user-defined conversions (so a class can be used where integral type is expected)

std::is_pod inherited from std::integral_constant的转换运算符是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 A template-argument for a non-type, non-template template-parameter shall be one of:

1.1 - for a non-type template-parameter of integral or enumeration type, a converted constant expression ([expr.const]) of the type of the template-parameter; or

[expr.const]

3 An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions ([conv.lval]), integral promotions ([conv.prom]), and integral conversions ([conv.integral]) other than narrowing conversions ([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

Microsoft 对模板的处理在历史上与 GCC 或 Clang 不同,这可能是解析中出现此问题的原因。