C++14 Different constexpr behavior between gnu and intel compiler related to NaN expressions (expression must have a constant value)

Viewed 137

We are currently in the working of including the latest intel compiler into our pipeline for a C++14 project, but I cannot figure out two specific sections that include NaN comparisons in constexpr classes, one of which is featured below as a minimum (non-)working example. The code compiles just fine with g++, but fails with icpc (code and output see below). The numeric_limits are constexpr in C++14 and also reimplementing them gave the same error, but if I comment out the two lines featuring NaN, the code compiles with 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;}

compilation

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)

intel compilation error

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)

Changing to

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

lets me compile with icpc

3 Answers

So still pretty sure this is an actual fault in the intel compiler.

Since I didn't want to remove the assert statement or the NaN check in the assert, the quick fix I ended up using was to replace the NaN comparison

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

with an equal to self comparison

absoluteTolerance == absoluteTolerance

assert is NOT on the list of things which are allowed in constexpr functions. It's a macro, so different compilers may expand it in different ways. Some of those expansions might just happen to be allowed in a constexpr function, but this is Unspecified. It is not a fault of any compiler if they chose to implement assert in a way that's incompatible with constexpr.

static_assert IS on the list of things allowed in constexpr functions.

@Holt, you are correct. Using -DNDEBUG you can get rid of the error.

Compilation command:icpc -DNDEBUG -std=c++14 mwe.cpp

You must #define NDEBUG (or use the flag -DNDEBUG) this will disable assert. The assert statement so far is executed at run time.

Related