简体   繁体   English

使模板功能对deinguish继承人和其他人

[英]Make template function to destinguish inheritors and others

I have a class ( base ) which has many inheritors ( derived_i ) and some other types ( other ). 我有一个类( base ),它有许多继承者( derived_i )和一些其他类型( other )。 I want to have a template method in some class-handler ( caller ), which handles inheritors of base in differ way, then from other types. 我想在一些类处理程序( caller程序)中有一个模板方法,它以不同的方式处理base继承者,然后从其他类型处理。

Here is an example code I telling about. 这是我讲述的示例代码。

#include <iostream>

using namespace std;

template <typename T>
class base {
public:
    base (T val = T())
        : m_val(val)
    {}
    base (const base &other)
        : base(other.m_val)
    {}
    virtual void base_specific_method()
    {
        cout << __func__ << " method called: " << m_val << endl;
    }
    void each_class_has_this() {
        cout << __func__ << " this is boring..." << endl;
    }
    T m_val;
};
class other {
public:
    void each_class_has_this() {
        cout << __func__ <<" this is boring..." << endl;
    }
};
class derived_i : public base <int>
{
public:
    derived_i () : base <int> (10)
    {}
    virtual void base_specific_method()
    {
        cout << __func__ <<" Hey! I'm interesting derived! And 10 == " << m_val << endl;
    }
};

template <typename T>
class caller {
public:
    caller (T val = T())
        : m_val(val)
    {}
    void call() {
        p_call(m_val);
    }
private:
    template <typename T1> void p_call (T1 &val)
    {
        val.each_class_has_this();
    }
    template <typename T1> void p_call (base<T1> &val)
    {
        val.base_specific_method();
    }
private:
    T m_val;
};

int main ()
{
    caller<other> c1;
    caller<base<double> > c2;
    caller<derived_i > c3;

    c1.call();
    c2.call();
    c3.call();
}

It compiled with g++ -std=c++11 test.cpp and output is next: 它用g++ -std=c++11 test.cpp ,输出如下:

  each_class_has_this this is boring...
  base_specific_method method called: 0
  each_class_has_this this is boring...

While I'm expecting 虽然我在期待

  each_class_has_this this is boring...
  base_specific_method method called: 0
  base_specific_method Hey! I'm interesting derived! And 10 == 10

Is there any way to change this code to make it suitable my requests? 有没有办法更改此代码,使其适合我的要求?

This question seems to be a duplicate of another question , but the correct answer on it leads to the problem, I faced here. 这个问题似乎是另一个问题的重复,但正确的答案会导致问题,我在这里面对。

PS There is no way to make base and other the inheritors from one class. PS没有办法从一个类中创建baseother继承者。 =( =(

You can get the desired behaviour using SFINAE: 您可以使用SFINAE获得所需的行为:

Add a class has_specific like this: 像这样添加一个类has_specific

template <typename T>
class has_specific
{
    typedef char one;
    typedef long two;

    template <typename C> static one test( typeof(&C::base_specific_method) ) ;
    template <typename C> static two test(...);    

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

And change your definition of p_call to this: 并将p_call的定义p_call为:

template <typename T1=T>
typename enable_if<!has_specific<T1>::value,void>::type
p_call (T1 &val)
{
    val.each_class_has_this();
}

template <typename T1=T>
typename enable_if<has_specific<T1>::value,void>::type
p_call (T1 &val)
{
    val.base_specific_method();
}

In this case i used the SFINAE in the return type. 在这种情况下,我在返回类型中使用了SFINAE。 It should be possible to use it in the template arguments list or in the parameters list as well, but this one was the one i got working first. 应该可以在模板参数列表或参数列表中使用它,但这个是我首先工作的那个。
As a technical detail, this implementation does not depend on if you have a class derived from base , but if a method base_specific_method() is present, but i hope it still helps with your problem. 作为一个技术细节,这个实现不依赖于你是否有一个派生自base的类,但是如果存在一个方法base_specific_method() ,但我希望它仍然有助于你的问题。

Try it online 在线尝试
has_specific taken from here has_specific取自此处
return type SFINAE taken from here 返回类型SFINAE取自此处

You can use std::enable_if with std::is_base_of to distinguish the class derived from base<T> or not. 您可以将std::enable_ifstd::is_base_of以区分派生自base<T>的类。

template <typename T, typename TT = void>
class caller {
public:
    caller (T val = T())
        : m_val(val)
    {}
    void call() {
        p_call(m_val);
    }
private:
    template <typename T1> typename std::enable_if<!std::is_base_of<base<TT>, T1>::value>::type p_call (T1 &val)
    {
        val.each_class_has_this();
    }
    template <typename T1> typename std::enable_if<std::is_base_of<base<TT>, T1>::value>::type p_call(T1& val)
    {
        val.base_specific_method();
    }

private:
    T m_val;
};

Note that base is a template class, which means T1 might be derived class of base<int> , or base<double> , and so on. 请注意, base是一个模板类,这意味着T1可能是base<int>base<double>派生类,依此类推。 We can't count all the possibilities, so the template parameter TT need to be specified as the hint. 我们无法计算所有可能性,因此需要将模板参数TT指定为提示。 Then use it as: 然后用它作为:

caller<other> c1;
caller<base<double>, double> c2;
caller<derived_i, int> c3;  // derived_i derived from base<int>

c1.call();
c2.call();
c3.call();

Result: 结果:

each_class_has_this this is boring...
base_specific_method method called: 0
base_specific_method Hey! I'm interesting derived! And 10 == 10

LIVE 生活

Or you can make a most base class to make it simple: 或者你可以创建一个最基础的类来使它变得简单:

class abstract_base {
public:
    virtual void base_specific_method() = 0;
    virtual ~abstract_base() {}
};
template <typename T>
class base : public abstract_base {
    ...
};
...
template <typename T>
class caller {
    ...
    template <typename T1> typename std::enable_if<!std::is_base_of<abstract_base, T1>::value>::type p_call (T1 &val)
    {
        val.each_class_has_this();
    }
    template <typename T1> typename std::enable_if<std::is_base_of<abstract_base, T1>::value>::type p_call(T1& val)
    {
        val.base_specific_method();
    }
    ...
};

LIVE2 LIVE2

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

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