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

Using SFINAE to disable template class member function

本文关键字:成员 函数 SFINAE 使用      更新时间:2023-10-16

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


我现在有一个类似的代码:

#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>的基类。

因此,Derived<T>::f()中的破解对于程序的编译是必要的;则CCD_ 11行永远不会被执行。

您可以简单地将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_();
}

不,不能排除使用SFINAE的成员函数。您可以通过Derivedf成员函数的专业化来将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();
  }
};

实时演示