class 方法的 SFINAE

SFINAE for class methods

文章 https://www.fluentcpp.com/2018/05/15/make-sfinae-pretty-1-what-value-sfinae-brings-to-code/ and https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ 解释了如何将 SFINAE 用于 class 方法。 class 的第一个实现如下:

template<typename T>
class MyClass
{
public:
    void f(T const& x);
    void f(T&& x);
};

防止使用第二个函数f如果T是引用,本文提出如下解决方案:

template<typename T>
class MyClass
{
public:
    void f(T const&  x){}

    template<typename T_ = T, typename = std::enable_if_t<!std::is_reference_v<T_>>>
    void f(T&& x){}
};

std::enable_if代替方法的return类型不就是easier/cleaner吗?所以 class 看起来像下面这样:

template<typename T>
class MyClass
{
public:
    void f(T const&  x){}

    std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
};

首先,你的技术不行。 TMyClass 中的固定类型 enable_if_t<false> 格式错误。没有执行替换,所以这不是替换失败,它只是一个格式错误的签名。

您可以通过

在一定程度上修复它
template<class T_=T>
std::enable_if_t<!std::is_reference_v<T_>>> f(T_&& x){}

现在,此技术(使用 return 值)不适用于 (A) 构造函数,以及 (B) 当您想推导 return 类型时。

它还混合了return类型和SFINAE代码;两者没有任何关系

最重要的是,这项技术和您正在复制的原始技术都与 "all templates must have a valid instantiation" 有一些可疑的交互。我仍然不清楚这是否适用于固定模板 class 实例化的每个模板方法;如果是这样,那么您必须确保某些 T_ 会使正文有效。

Wouldn't it be easier/cleaner to substitute the return type of the method by enable_if?

我想是个人品味问题。

总之,考虑一下你的例子

std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}

不起作用,因为 SFINAE 在特定方法的模板上工作。因此,同样对于您的示例,您必须使用 T_(我称之为 U)模板类型并且条件 std::is_reference 必须计算 U,而不是 T

template <typename U = T>
std::enable_if_t<!std::is_reference_v<U>> f(T&& x){}

无论如何,这两种解决方案都存在 "hijacking" 风险:您可以绕过说明 U 类型

的测试
myClassObject.template f<void>(aReference);

为避免劫持风险,您还必须强加 TU 是同一类型

template<typename U = T,
         typename = std::enable_if_t<
            !std::is_reference_v<U>
            && std::is_same_v<U, T>>>
void f(T&& x){}

template <typename U = T>
std::enable_if_t<
   !std::is_reference_v<U>
   && std::is_same_v<U, T>> f(T&& x)
 { }