繁体   English   中英

如何基于模板化类的基类专门化成员函数

[英]How do I specialize member functions based on the base class of the templated class

我试图根据模板的类型来专门化模板类的成员函数。 我特别希望基于多态类型的专业化。 我一直在努力的语法。 这是我的尝试,它显然会产生错误: 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正常工作,必须在doSomething模板参数而不是MyClass参数上执行SFINAE检查。 最后,您的支票错了。

所以这是我的版本:

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干净的解决方案:

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();
    }
};

另一个可能的解决方案是通过ForFoo模板类,该模板类定义foo()方法,并且对仅Base类和Derived类具有两个特殊化。 因此MyClass<T>可以从ForFoo<T>继承。

我的意思是...如果您按以下方式定义ForFoo模板类集

template <typename T, typename = void>
struct ForFoo
 { void foo () { std::cout << "other type" << std::endl; } };

template <typename T>
struct ForFoo<T,
   typename std::enable_if<std::is_base_of<Base, T>::value
                        && ! std::is_base_of<Derived, T>::value>::type>
 { void foo () { std::cout << "Base type" << std::endl; } };

template <typename T>
struct ForFoo<T,
   typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
 { void foo () { std::cout << "Derived type" << std::endl; } };

MyClass变成

template <typename T>
struct MyClass : public ForFoo<T>
 { };

以下是完整的C ++ 11示例

#include <iostream>
#include <type_traits>

class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};

template <typename T, typename = void>
struct ForFoo
 { void foo () { std::cout << "other type" << std::endl; } };

template <typename T>
struct ForFoo<T,
   typename std::enable_if<std::is_base_of<Base, T>::value
                        && ! std::is_base_of<Derived, T>::value>::type>
 { void foo () { std::cout << "Base type" << std::endl; } };

template <typename T>
struct ForFoo<T,
   typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
 { void foo () { std::cout << "Derived type" << std::endl; } };

template <typename T>
struct MyClass : public ForFoo<T>
 { };

int main ()
 {
   MyClass<Base>{}.foo();      // Base
   MyClass<Derived>{}.foo();   // Derived
   MyClass<A>{}.foo();         // Base
   MyClass<B>{}.foo();         // Derived
   MyClass<X>{}.foo();         // other
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM