[英]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没有办法从一个类中创建base
和other
继承者。 =( =(
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_if
与std::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
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();
}
...
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.