c++ - 如何根据模板类的基类专门化成员函数

标签 c++ c++11 templates sfinae template-specialization

我正在尝试根据模板类型专门化模板类的成员函数。特别是我想要基于多态类型的特化。我一直在为语法而苦苦挣扎。这是我的尝试,它显然会产生错误:doSomething()

声明中的两个或多个数据类型
class Base {};
class Derived : public Base {};

template<typename T>
class MyClass
{
public:

  void doSomething();

};

template<>
template<typename T>
typename std::enable_if<std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething() 
{
    // Do something with Derived type
}

template<>
template<typename T>
typename std::enable_if<std::is_base_of<Base, T>::value &&
                       !std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething() 
{
    // So something with Base type
}

template<>
template<typename T>
typename std::enable_if<!std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething() 
{
    // Do something with all other types
}

编译给出..

error: two or more data types in declaration of 'doSomething'

顺便说一句,我确实编译了以下内容,但是特化在运行时没有按预期工作。基础类型和派生类型最终会通过 doSomething() 的非专用版本。

class Base {};
class Derived : public base {};

template<typename T>
class MyClass
{
public:

  void doSomething()
  {
       // Do something for non-specialized types
  }    
};

template<>
void MyClass<Derived>::doSomething() 
{
    // Do something with Derived type
}

template<>
void MyClass<Base>::doSomething() 
{
    // So something with Base type
}

正确的语法是什么?

最佳答案

您不能仅仅因为 doSomething 不是模板就专门化它。 MyClass 是一个模板,您可以专门化该类,每个专门化都有一个 doSomething。如果这不是您想要的,那么您需要进行 doSomething 模板重载,并且为了使 SFINAE 正常工作,SFINAE 检查必须在 doSomething 模板参数上进行,而不是在MyClass 参数。最后,您的支票有误。

这是我的版本:

template<class T> struct MyClass
{
    template <class U = T>
    auto foo() -> std::enable_if_t<std::is_base_of_v<Base, U>
                                   && !std::is_base_of_v<Derived, U>>
    {
        foo_base();
    }

    template <class U = T>
    auto foo() -> std::enable_if_t<std::is_base_of_v<Derived, U>>
    {
        foo_derived();
    }

    template <class U = T>
    auto foo() -> std::enable_if_t<!std::is_base_of_v<Base, U>>
    {
        foo_else();
    }
};

这是一组测试:

class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};
auto test()
{
    MyClass<Base>{}.foo();      // foo_base
    MyClass<Derived>{}.foo();   // foo_derived
    MyClass<A>{}.foo();         // foo_base
    MyClass<B>{}.foo();         // foo_derived
    MyClass<X>{}.foo();         // foo_else
}

当然我必须提到 C++17 clean 解决方案:

template<class T> struct MyClass
{
    auto foo() 
    {
        if constexpr (std::is_base_of_v<Derived, T>)
            foo_derived();
        else if constexpr (std::is_base_of_v<Base, T>)
            foo_base();
        else
            foo_else();
    }
};

关于c++ - 如何根据模板类的基类专门化成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52901436/

相关文章:

c++ - 在 C++ 中读取二进制文件返回意外值

c++ - 如何使用已删除的复制构造函数初始化类数组(C++11)

c++ - 通过非线程局部对象访问的线程局部变量

c++ - 在 C++ 中接受 "anything"的模板

unit-testing - Nim 中的单元测试 : Is it possible to get the name of a source file at compile time?

python - 通过套接字在C++和python之间交换固定 float 组

javascript - NAPI 插件 : how to return value to javascript from c++ CALLBACK?

c++ - 为什么 xvalue 不绑定(bind)到非常量左值引用?

C++ 模板元编程- 不确定我是否大惊小怪?

c++ - boost::archive::text_iarchive 构造函数异常