std::enable_if 与非即时上下文中的硬错误

std::enable_if vs hard errors in non-immediate context

根据 SFINAE 在 cpprefence

上的描述

Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier (since C++20) are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors.

特别是,当我下面的代码中的 Helper<T> 在模板参数推导期间被实例化时,我收到了一个错误,正如预期的那样。所以这是我的问题:为什么 std::enable_if 与 SFINAE,即使它是一个必须实例化的结构(并且通常与 很多类型特征结构也在这个过程中被实例化)。

这是代码

#include<iostream>
#include<type_traits>

template<typename T, typename U = typename T::my_type>
void sfinae(const T&) { std::cout << "template\n"; }

void sfinae(...) { std::cout << "non template\n"; }

template<typename T>
struct Helper{
    using my_type = typename T::my_type;
};

template<typename T, typename U = typename Helper<T>::my_type>
void hardError(const T&) { std::cout << "template\n"; }

void hardError(...) { std::cout << "non template\n"; }


struct NonEmpty{ using my_type=int; };
struct Empty{ };


int main()
{
    NonEmpty ne;
    Empty e;

    sfinae(ne);     //template overload called
    hardError(ne);  //template overload called

    sfinae(e);      //non-template overload called

    hardError(e);   //hard error 

}

std::enable_if 的可能实现是

template <bool cond, typename T = void> struct enable_if;
template <typename T> struct enable_if<false, T>{};
template <typename T> struct enable_if<true, T>{ using type = T; };

所以enable_if不会产生硬错误。实例化 std::enable_if<false> 有效。

实例化 Helper<Empty>Empty::type 上产生错误,这不是在 SFINAE 的直接上下文中完成的,因此是硬错误。

std::enable_ifstd::void_t 与 SFINAE 配合得很好,因为它们提供了在直接上下文中失败的简单方法:

std::enable_if<cond_v<T>, int>::type = 0typename AlwaysVoid = std::void_t<decltype(dependent_expression)>.