C++14与NaN表达式相关的gnu和intel编译器之间的不同constexpr行为(表达式必须有常量值)

kmb7vmvb  于 2023-07-01  发布在  其他
关注(0)|答案(3)|浏览(98)

我们目前正在将最新的英特尔编译器纳入到我们的C14项目的管道中,但我无法找出两个特定的部分,其中包括constexpr类中的NaN比较,其中一个是作为最低(非)工作示例。代码在g下编译得很好,但在icpc下编译失败(代码和输出见下文)。numeric_limits在C++14中是constexpr,重新实现它们也会出现同样的错误,但是如果我注解掉包含NaN的两行,代码将使用icpc编译

mwe.h

#include <cassert>
#include <limits>
#include <math.h>

inline constexpr double toRadians(const double inDegrees) noexcept {
  return M_PI * inDegrees / 180;
}

template<typename T>
class ExpandedAbsoluteEqualityComparator {
private:
  const T absoluteTolerance_;

public:
  constexpr ExpandedAbsoluteEqualityComparator(const T absoluteTolerance)
    : absoluteTolerance_(absoluteTolerance)
  {
    assert(
      absoluteTolerance > 0
      && absoluteTolerance != std::numeric_limits<T>::infinity()
      && absoluteTolerance != std::numeric_limits<T>::quiet_NaN()
      && absoluteTolerance != std::numeric_limits<T>::signaling_NaN()
    );
  }
};

class SomeClass {
public:
  //! 1° absolute tolerance floating point comparison helper for angle groups
  static constexpr ExpandedAbsoluteEqualityComparator<const double> fpComparator {
    toRadians(1.0)
  };
};

mwe.cpp

#include "mwe.h"
int main() {return 0;}

编译

g++ -pedantic -std=c++14 mwe.cpp  # works (version 10.1.0)
icpc -std=c++14 mwe.cpp  # fails (version icpc (ICC) 2021.4.0 20210910)

英特尔编译错误

In file included from mwe.cpp(1):
mwe.h(30): error: expression must have a constant value
    static constexpr ExpandedAbsoluteEqualityComparator<const double> fpComparator {
                                                                                   ^
mwe.h(18): note: floating-point values cannot be compared
      assert(
      ^

compilation aborted for mwe.cpp (code 2)

变更为

//&& absoluteTolerance != std::numeric_limits<T>::quiet_NaN()
    //&& absoluteTolerance != std::numeric_limits<T>::signaling_NaN()

让我用icpc编译

ehxuflar

ehxuflar1#

所以仍然很确定这是intel编译器中的实际错误。
因为我不想删除assert语句或assert中的NaN检查,所以我最终使用的快速解决方法是替换NaN比较

absoluteTolerance != std::numeric_limits<T>::quiet_NaN() && absoluteTolerance != std::numeric_limits<T>::signaling_NaN()

与自身比较

absoluteTolerance == absoluteTolerance
koaltpgm

koaltpgm2#

assert不在constexpr函数允许的列表中。它是一个宏,所以不同的编译器可以用不同的方式扩展它。其中一些扩展可能恰好在constexpr函数中被允许,但这是未指定的。如果编译器选择以与constexpr不兼容的方式实现assert,这不是任何编译器的错。
static_assertconstexpr函数允许的列表中。

g6baxovj

g6baxovj3#

你说得对。使用-DNDEBUG可以消 debugging 误。
编译命令:icpc -DNDEBUG -std=c++14 mwe.cpp
你必须#define NDEBUG(或者使用-DNDEBUG标志),这将禁用assert。到目前为止,assert语句是在运行时执行的。

相关问题