MSVC 和 clang for if constexpr 分支的不同行为
Different behavior of MSVC and clang for if constexpr branches
给定此辅助函数:
template<typename Type>
std::string toString(Type const& value, bool encloseInQuotes = false) {
if constexpr (std::is_same<bool, Type>::value) {
auto s = value ? "true" : "false";
return encloseInQuotes ? """s + s + """ : s;
}
if constexpr (std::is_arithmetic<Type>::value) {
if (std::isnan(value)) {
return encloseInQuotes ? ""NaN"" : "NaN";
}
}
return "";
}
它应该将基本类型(和字符串)转换为字符串表达式,当像这样使用它时,我收到 MSVC 的编译错误:
int main() {
std::string temp = toString(true);
return 0;
}
使用clang,编译没有任何问题,使用MSVC,我得到这个:
2>c:\程序文件 (x86)\Windows 工具包\10\include\10.0.10240.0\ucrt\math.h(403):错误 C2668:"fpclassify":对重载函数的不明确调用
2>c:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt\math.h(288): 注意:可能是'int fpclassify(long double) noexcept'
2>c:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt\math.h(283): 注意:或 'int fpclassify(double) noexcept'
2>c:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt\math.h(278): 注意:或 'int fpclassify(float) noexcept'
2>c:\程序文件 (x86)\Windows 工具包\10\include\10.0.10240.0\ucrt\math.h(403): 注意:尝试匹配参数列表"(_Ty)"时
2>
2> [
2> _Ty=整数
2> ]
2>:注意:请参阅正在编译的函数模板实例化"bool isnan(_Ty) noexcept"的参考
2>
2> [
2> 类型=整数,
2> _Ty=整数
2> ]
显然,编译器也将if constexpr (std::is_arithmetic<Type>::value)
测试视为有效的替代方案,并生成上述错误。但是,在运行时,它正确地采用布尔值的路径(当我省略if constexpr (std::is_arithmetic<Type>::value)
部分或使用铸造if (std::isnan(static_cast<double>(value)))
时)。
我怎样才能在 Windows 上正确编译它?
对于bool
,至少有两个类型特征返回true
:
std::is_same<bool, Type>::value
std::is_arithmetic<Type>::value
然后你打电话std::isnan(true)
.使用else if
:
if constexpr (std::is_same<bool, Type>::value) {
auto s = value ? "true" : "false";
return encloseInQuotes ? """s + s + """ : s;
}
else if constexpr (std::is_arithmetic<Type>::value) {
if (std::isnan(value)) {
return encloseInQuotes ? ""NaN"" : "NaN";
}
...
}
else
return "";
std::isnan
和std::isinf
似乎在MSVC中内部调用fpclassify
。此函数对于浮点类型是重载的,并且您传递了类型bool
的参数,因此调用是不明确的。
为了避免这种情况,您可以将参数转换为double
:
if constexpr (std::is_arithmetic<Type>::value) {
if (std::isinf((double)value)) {
return encloseInQuotes ? ""INF"" : "INF";
}
if (std::isnan((double)value)) {
return encloseInQuotes ? ""NaN"" : "NaN";
}
现场演示:https://godbolt.org/z/W7Z3r3
更新
这似乎是 MSVC 实现中的一个错误,因为根据 cpp 首选项,应该有一个与double
重载行为相同的积分参数的重载。最小示例:
auto b = std::isnan(1);
现场演示:https://godbolt.org/z/qcTfQs
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 多成员Constexpr结构初始化
- 条件constexpr函数
- IPC使用多个管道和分支进程来运行Python程序
- constexpr 函数中的非文字(通过 std::is_constant_evaluated)
- Visual C++ constexpr Hints
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么constexpr的性能比正常表达式差
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 如何删除peer if else分支中的冗长句子
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 丢弃分支中的嵌套 constexpr-if 语句仍在计算?
- 从“if constexpr”分支扩展对象生存期/范围
- MSVC 和 clang for if constexpr 分支的不同行为
- 禁用具有"if constexpr"和 SFINAE 的分支
- 如果ConstexPR编译了错误分支的时间崩溃
- constexpr求值的分支/constexpr的重载
- if constexpr的False分支未在模板化lambda中丢弃
- 编译器是否可以在 constexpr 函数中省略"not-taken"分支的计算?