隐式转换应该在模板参数的上下文中工作吗?
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 不同,这可能是解析中出现此问题的原因。
更明确地说,编译器是否应该在 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 typeT
, 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 不同,这可能是解析中出现此问题的原因。