当 require 子句失败时,函数尾随 return 类型是否被评估

Is function trailing return type evaluated when requires clause fails

下面或 godbolt 上的简单代码不能用 clang 编译,但可以用 gcc 和 Visual Studio.

编译。

当 SFINAE 因 clang、gcc 和 Visual Studio.

失败时,baz(T t) 的尾随 return 类型 decltype(foo(t)) 未被评估

但是,当 requires 子句因 clang 失败时,bar(T t) 的尾随 return 类型 decltype(foo(t)) 仍会被评估。当 gcc 和 Visual Studio 的 requires 子句失败时,不会评估尾随 return 类型。哪个编译器对此是正确的?

谢谢。

#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
}

这是 CWG 2369,clang 似乎还没有实现。

那个问题中的示例(现在可以在 [temp.deduct.general]/5 中找到)不能在 clang 上编译,但可以在 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
}