如果constexpr分支,则MSVC和clang的不同行为

Mik*_*hke 16 c++

鉴于此辅助功能:

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 "";
}
Run Code Online (Sandbox Code Playgroud)

应该将基本类型(和字符串)转换为字符串表达式,使用MSVC时出现如下编译错误:

int main() {
  std::string temp = toString(true);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用clang可以毫无问题地进行编译,但是使用MSVC可以得到:

2> c:\ program files(x86)\ windows kits \ 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:\ program files(x86)\ windows kits \ 10 \ include \ 10.0.10240.0 \ ucrt \ math.h(403):注意:在尝试匹配参数列表'(_Ty)'时

2>与

2> [

2> _Ty = int

2>]

2>:注意:请参见对正在编译的函数模板实例化'bool isnan(_Ty)noexcept'的引用

2>与

2> [

2> Type = int,

2> _Ty = int

2>]

显然,编译器也将if constexpr (std::is_arithmetic<Type>::value)测试视为有效的替代方法,并产生上述错误。但是,在运行时,它正确地采用了bool的路径(当我省略if constexpr (std::is_arithmetic<Type>::value)零件或使用cast时if (std::isnan(static_cast<double>(value))))。

我如何也可以在Windows上正确进行编译?

Evg*_*Evg 8

对于bool至少两个类型特征返回true

std::is_same<bool, Type>::value
std::is_arithmetic<Type>::value
Run Code Online (Sandbox Code Playgroud)

然后您打电话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 "";
Run Code Online (Sandbox Code Playgroud)


Dan*_*ica 7

std::isnan并且std::isinf似乎在内部调用fpclassifyMSVC。对于浮点类型,此函数已重载,并且您传递了type的参数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";
  }
Run Code Online (Sandbox Code Playgroud)

现场演示:https : //godbolt.org/z/W7Z3r3


更新

这似乎是MSVC实现中的错误,因为根据cppreference,对于整数参数,应该有与重载相同的double重载。最小示例:

auto b = std::isnan(1);
Run Code Online (Sandbox Code Playgroud)

现场演示:https : //godbolt.org/z/qcTfQs