C ++动态检测参数类并强制转换 [英] C++ Dynamically detect class of parameter and cast thereto

查看:160
本文介绍了C ++动态检测参数类并强制转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类,一个从另一个继承。基类的相关部分如下(显然这个类有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 code>。让我们建立它。



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.)

Vectors print out one way (e.g. < 3, 5, 1 >); Polynomials print out another (e.g. 3 x^2 + 5 x + 1).

This causes a problem, though. When I go to add two Polynomials 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 Polynomials 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆