使用 SFINAE 禁用模板 class 成员函数

Using SFINAE to disable template class member function

是否可以使用 SFINAE 和 std::enable_if 禁用模板的单个成员函数 class?


我目前有一个类似这样的代码:

#include <type_traits>
#include <iostream>
#include <cassert>
#include <string>

class Base {
public:
    virtual int f() { return 0; }
};

template<typename T>
class Derived : public Base {
private:
    T getValue_() { return T(); }

public:
    int f() override {
        assert((std::is_same<T, int>::value));
        T val = getValue_();
        //return val; --> not possible if T not convertible to int
        return *reinterpret_cast<int*>(&val);
    }
};


template<typename T>
class MoreDerived : public Derived<T> {
public:
    int f() override { return 2; }
};


int main() {
    Derived<int> i;
    MoreDerived<std::string> f;
    std::cout << f.f() << " " << i.f() << std::endl;
}

理想情况下,如果 T != int,则应禁用 Derived<T>::f()。因为 f 是虚拟的,所以 Derived 的任何实例化都会生成 Derived<T>::f(),即使它从未被调用。 但是使用代码使得 Derived<T>(带有 T != int)永远不会仅作为 MoreDerived<T>.

的基础 class 创建

因此 Derived<T>::f() 中的 hack 是编译程序所必需的; reinterpret_cast 行永远不会执行。

不,您不能排除 SFINAE 的成员函数。您可以通过将 Derived class f 成员函数特化以将 T 转换为 int 来实现,但这会导致不必要的代码重复。然而,在 C++17 中,您可以使用 if constexpr:

来解决这个问题
template<typename T> class Derived : public Base {
  T getValue_() { return T(); }
public:
  int f() override {
    if constexpr(std::is_convertible<T, int>::value) return getValue_();
    return Base::f();
  }
};

Live Demo

您可以简单地将 f 专门化为 int:

template<typename T>
class Derived : public Base {
private:
    T getValue_() { return T(); }

public:
    int f() override {
        return Base::f();
    }
};

template <>
int Derived<int>::f () {
    return getValue_();
}