关于 sfinae 默认参数值的实现分歧

Gui*_*cot 7 c++ templates sfinae language-lawyer c++20

我生成了一个存在实现分歧的代码,我想知道哪个编译器是正确的以及为什么,或者标准的哪一部分允许这些编译器有所不同:

#include <type_traits>
#include <cstdio>

// Only deleted when the constraint is not met
template<typename T>
struct deleted {
    template<typename U = T> requires (not std::is_integral_v<U>)
    deleted() = delete;

    template<typename U = T> requires std::is_integral_v<U>
    deleted() {}
};

struct trigger_error {
    template<typename F>
    operator F () {
        static_assert(not std::is_same_v<F, F>, "Cannot call f with floating point types");
        return F{};
    }
};

// Constrained function. Only callabale with integral types
// When called with something other than integral, display static assert.
// sfinae still applies even though the static assert is called.
template<typename T> requires std::is_integral_v<T>
void f(T) {}

template<typename T> requires (not std::is_integral_v<T>)
auto f(T, int = trigger_error{}, deleted<T> = {}) {};

// Do sfinae if f is callable. If callable, prints "integrals"
template<typename T> requires(requires(T t){f(t);})
auto use_constrains(T) -> void {
    puts("integrals");
}

// Sfinae fails, print "floats" instead
template<typename T>
auto use_constrains(T) -> void {
    puts("floats");
}

int main() {
    use_constrains(1);
    //f(1.3); // uncommenting triggers static assert
    use_constrains(1.3);
}
Run Code Online (Sandbox Code Playgroud)

运行在编译器资源管理器上

令我惊讶的是,代码甚至没有在 Clang 上编译,并且在调用已删除函数时出现硬错误deleted::deleted()

MSVC 进行编译,但不执行 sfinae,也不执行硬错误,只是"integrals"在两次调用上进行打印。

由于这三种实现方式存在差异,我想知道谁是正确的以及为什么。sfinae 是否应用于参数默认值的表达式?