C ++动态检测参数类并强制转换 [英] C++ Dynamically detect class of parameter and cast thereto
问题描述
我有两个类,一个从另一个继承。基类的相关部分如下(显然这个类有ctors,dtor等,特别是 operator []
,但我认为那些不相关的
#include< array>
template<类T,无符号整数N>
class Vector
{
public:
template< class U,unsigned int M>朋友矢量& U,M>运算符+(const Vector< U,M&& const vector< U,M&
template< class U,unsigned int M> friend std :: ostream&运算符<< (std :: ostream& amp; const Vector< U,M>&);
};
派生类(很显然,我已经拿出了那些我认为不相关的部分):
#includeVector.h
template<类T,无符号整数N>
类多项式
:public Vector< T,N>
{
public:
template< class U,unsigned int M> friend std :: ostream&运算符<< (std :: ostream& const Polynomial< U,M>&);
};
(注意:friend函数使用不同的字母为模板比类做,因为否则gcc的抱怨关于阴影,逻辑也是一样的。)
向量
< 3,5,1>
); 多项式
打印出另一个(例如 3 x ^ 2 + 5 x + 1
)。
但这会导致一个问题。当我去添加两个多项式
在一起,编译器使用 template< class U,unsigned int M>另外, U,M>运算符+(const Vector< U,M>& const Vector< U,M>&)
,当然返回 Vector
。因此,如果我尝试做 std :: cout<<
我想修改 template< class U,unsigned int M>另外, U,M>运算符+(const Vector< U,M&& const Vector< U,M>&)
,使得它将检测其参数的实际数据类型, (例如,如果将两个多项式
传递给它,则返回多项式
)。我想这样做,如果可能,没有运算符+
知道每个可能的子类 Vector
这可能是一个合法的愿望?),并且没有为每个子类创建一个新的操作符+
函数(因为我还有其他重载的操作符,并且希望避免复制几乎完全对于每个派生类,相同的代码十次)。
我知道这是可能的(事实上,相对容易)在Python。如果计算结果为 Vector< T,N>< T>
,您不能简单地(合法地)将其转换为多项式< T,N>
。要实现所需的效果,您需要一些更深入的修改。你需要一个自由的运算符+
,这个实现可以提供所需的结果类型,并且可以检测从 Vector
a)检测所有向量< T,N>
为此,你可以派生一个空的基类,它将被空基本优化(EBO)优化,并且可以通过 std :: enable_if
:
struct VectorBase {};
template<类T,无符号整数N>
class Vector
{
// ...
};
现在可以检查任何类 U
if它源自 Vector< T,N>
与 std :: is_base_of< VectorBase,U> :: value
。为了绝对正确,你需要排除 VectorBase
本身(!std :: is_same ),但是这可能不是您的用例所需要的。
b)一个实现,它提供所需的返回类型。 之前我们这样做:
类T,无符号整数N>
class Vector
{
template< class U,unsigned int M>
friend Vector< U,M>运算符+(const Vector< U,M&& const vector< U,M&
};
应替换为:
template<类T,无符号整数N>
class Vector
{
friend Vector< T,N>运算符+(const Vector< T,N& amp; const Vector< T,N&
};
但是你需要一个特殊的返回类型,以后可以成为多项式< T,N>
,所以:
template<类T,无符号整数N>
class Vector
{
public:
template<类型名R>
static R add(const Vector< T,N>& lhs,const Vector< T,N&>& rhs)
{
static_assert(std :: is_base_of& R> :: value,
R需要从Vector< T,N>中导出;
R result;
//在这里实现...
return result;
}
};
c)提供运算符+
code> add 并且受SFINAE保护:
//作为自由函数:
template<类型名V>
typename std :: enable_if< std :: is_base_of< VectorBase,V> :: value,V> :: type
operator +(const V& lhs,const V& rhs)
{
return V :: template add< V& 1hs,rhs);
}
减少一些小错字(我没有测试它),这个策略应该为你工作。
I have two classes, one which inherits from the other. The relevant part of the base class is as follows (obviously this class has ctors, a dtor, etc., and particularly an operator[]
, but I thought those irrelevant to the matter at hand):
#include <array>
template < class T, unsigned int N >
class Vector
{
public:
template < class U, unsigned int M > friend Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& );
template < class U, unsigned int M > friend std::ostream& operator<< ( std::ostream&, const Vector< U, M >& );
};
The derived class (again, obviously I've taken out those parts which I thought irrelevant):
#include "Vector.h"
template < class T, unsigned int N >
class Polynomial
: public Vector< T, N >
{
public:
template < class U, unsigned int M > friend std::ostream& operator<< ( std::ostream&, const Polynomial< U, M >& );
};
(Note: The friend functions use different letters for the templates than the classes do, because otherwise gcc complains about "shadowing". The logic is the same, though.)
Vector
s print out one way (e.g. < 3, 5, 1 >
); Polynomial
s print out another (e.g. 3 x^2 + 5 x + 1
).
This causes a problem, though. When I go to add two Polynomial
s together, the compiler uses template < class U, unsigned int M > Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& )
, which of course returns a Vector
. Therefore, if I try to do something like std::cout << poly1 + poly2;
, the resultant display is in the wrong format.
I would like to modify template < class U, unsigned int M > Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& )
such that it will detect the actual data types of its parameters, and cast the return value accordingly (e.g. return a Polynomial
if two Polynomial
s are passed to it). I would like to do this, if possible, without operator+
knowing about each and every possible subclass of Vector
(I think this is probably a legitimate desire?), and without making a new operator+
function for each subclass (since I also have several other overloaded operators, and would like to avoid copying almost exactly the same code ten times for each derived class).
I know that this is possible (and, in fact, relatively easy) in Python. Does C++ support such a thing?
If you calculate the result as Vector<T,N>
, you can not simply (legally) cast it to Polynomial<T,N>
. To achieve the desired effect, you need some deeper modifications. You need a free operator+
, an implementation that can deliver the desired result type and a way to detect everything derived from Vector<T,N>
. Let's build it.
a) Detect all Vector<T,N>
For that, you could derive from an empty base class that will be optimized away by the empty base optimization (EBO) and that is detectable by std::enable_if
:
struct VectorBase {};
template< class T, unsigned int N >
class Vector
{
// ...
};
now you can check any class U
if it's derived from Vector< T, N >
with std::is_base_of< VectorBase, U >::value
. To be absolutly correct, you need to exclude VectorBase
itself (!std::is_same< U, VectorBase >::value
), but that is probably not needed for your use case.
b) An implementation, that deliveres the desired return type. Before we do that:
template< class T, unsigned int N >
class Vector
{
template < class U, unsigned int M >
friend Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& );
};
should be replaced by:
template< class T, unsigned int N >
class Vector
{
friend Vector< T, N > operator+ ( const Vector< T, N >&, const Vector< T, N >& );
};
for the general case. But you need a special return type which can later become Polynomial<T,N>
, so:
template< class T, unsigned int N >
class Vector
{
public:
template< typename R >
static R add( const Vector< T, N >& lhs, const Vector< T, N >& rhs )
{
static_assert( std::is_base_of<VectorBase,R>::value,
"R needs to be derived from Vector<T,N>" );
R result;
// implement it here...
return result;
}
};
c) Provide an operator+
that calls add
and that is protected by SFINAE:
// as a free function:
template< typename V >
typename std::enable_if< std::is_base_of< VectorBase, V >::value, V >::type
operator+( const V& lhs, const V& rhs )
{
return V::template add<V>( lhs, rhs );
}
Minus some small typos (I haven't tested it), this strategy should work for you.
这篇关于C ++动态检测参数类并强制转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!