Home > Blockchain >  Is function trailing return type evaluated when requires clause fails
Is function trailing return type evaluated when requires clause fails

Time:06-01

Simple code as below or as on godbolt doesn't compile with clang but compiles fine with gcc and Visual Studio.

The trailing return type decltype(foo(t)) of baz(T t) is not evaluated when SFINAE fails with clang, gcc and Visual Studio.

However, the trailing return type decltype(foo(t)) of bar(T t) is still evaluated when requires clause fails with clang. The trailing return type is not evaluated when requires clause fails with gcc and Visual Studio. Which compiler is correct on this?

Thank you.

#include <utility>
#include <type_traits>

template<typename T>
auto foo(T) {
    static_assert(std::is_integral<T>::value); // clang error: static_assert failed due to requirement 'std::is_integral<double>::value'
    return 5;
}
 
template<typename T> requires std::is_integral<T>::value
auto bar(T t) -> decltype(foo(t)) {
    return foo(t);
}

template<typename T> requires (!std::is_integral<T>::value)
auto bar(T) {
    return 1.5;
}

template<typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
auto baz(T t) -> decltype(foo(t)) {
    return foo(t);
}

template<typename T, std::enable_if_t<!std::is_integral<T>::value>* = nullptr>
auto baz(T) {
    return 1.5;
}

int main()
{
    bar(5.); // fails with clang, works with gcc and VS
    baz(5.); // works with clang, gcc and VS
}

CodePudding user response:

This is CWG 2369, which clang does not appear to implement yet.

The example in that issue (which can now be found in [temp.deduct.general]/5) doesn't compile on clang, but does on gcc.

template <class T> struct Z {
  typedef typename T::x xx;
};
template <class T> concept C = requires { typename T::A; };
template <C T> typename Z<T>::xx f(void *, T); // #1
template <class T> void f(int, T);             // #2

struct A {} a;

struct ZZ {
  template <class T, class = typename Z<T>::xx> operator T *();
  operator int();
};

int main() {
  ZZ zz;
  f(1, a);   // OK, deduction fails for #1 because there is no conversion from int to void*
  f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied
}
  • Related