Home > Software design >  Is the microsoft C compiler smart enough to know std::isnan isn't called on a integral type i
Is the microsoft C compiler smart enough to know std::isnan isn't called on a integral type i

Time:04-14

This is related to my earlier post 'fpclassify': ambiguous call to overloaded function

I attempted to correct the code that produced the error. The original code looked like the following.

struct alignas(1) wrapped_int8 {
  using underlying = int8_t;
  int8_t value;
  // some other function definitions
};

template <typename T>
void func(T val) {
  auto mask = std::isnan(val);
}

int main(int argc, char const *argv[])
{  
  func<wrapped_int8::underlying>(4);
}

It failed to compile using microsoft compilers because of the fpclassify overload ambiguity issue and the lack of an integral overload to fpclassify for the microsoft build.

So I changed the func to:

template <typename T>
void func(T val) {
  auto mask = std::is_integral<T>::value ? false : std::isnan(val);
}

but this still gives the same error. With my code's logic, if T is an integral type, we should never have to call std::isnan, so there shouldn't be an issue with fpclassify, but is the compiler smart enough to know that std::isnan won't be called on integral types? If so, why is it still producing this error? If not, how can I fix this problem?

CodePudding user response:

you can use if constexpr to discard the call to std::isnan(val).

template <typename T>
void func(T val) {
  auto mask = [&] {
    if constexpr (std::is_integral_v<T>)
      return false;
    else
      return std::isnan(val);
  }();
}

C 14 version

template<class T>
constexpr typename std::enable_if<std::is_integral_v<T>, bool>::type 
mask_impl(T val) {
  return false;
}

template<class T>
constexpr typename std::enable_if<std::is_floating_point_v<T>, bool>::type 
mask_impl(T val) {
  return std::isnan(val);
}

template <typename T>
void func(T val) {
  auto mask = mask_impl(val);
}

CodePudding user response:

If C 17 is allowed

template <typename T>
void func(T val) {
  auto mask = false;
  if constexpr (!std::is_integral<T>::value)
    mask = std::isnan(val);
}

If C 14 or older

template <typename T>
void func(T val) {
  auto mask = std::isnan(val);
}

template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void func(T val) {
  auto mask = false;
}

You also may hack std::isnan for int8_t

namespace std {
  bool isnan(int8_t val) noexcept { return false; }
}
  • Related