c + +动态检测类参数及演员于此(C++ Dynamically detect class of

2019-10-17 21:23发布

我有两个班,一个从其他继承。 基类的相关部分如下(显然这类有构建函数,一个析构函数,等,且特别的operator[]但我认为那些不相关的手头的物质):

#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 >& );
};

派生类(再次,很明显我已经采取了我认为无关紧要的部分):

#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 >& );
};

(注:友元函数使用不同的字母比班做模板,否则GCC抱怨说“阴影”的逻辑是一样的,虽然。)

Vector S打印出单程(例如< 3, 5, 1 > ); Polynomial S打印出另一个(例如3 x^2 + 5 x + 1 )。

这会导致一个问题,虽然。 当我去添加两个Polynomial小号一起,编译器使用template < class U, unsigned int M > Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& )其当然返回一个Vector 。 因此,如果我尝试做类似std::cout << poly1 + poly2; 时,所得的显示是在错误的格式。

我想修改template < class U, unsigned int M > Vector< U, M > operator+ ( const Vector< U, M >&, const Vector< U, M >& )使得其将检测的实际数据类型它的参数,并且相应地将返回值(例如返回一个Polynomial如果两个Polynomial s的传递给它)。 我想这样做,如果可能的话,没有operator+了解关于每个和每一个可能子Vector (我认为这可能是一个合法的愿望是什么?),并且没有发生新的operator+功能的每个子类(因为我也有其他几个重载操作符,并希望避免复制几乎完全一样的代码十倍每个派生类)。

我知道这是可能的(并且,事实上,比较容易)在Python。 请问C ++支持这样的事情?

Answer 1:

如果计算出的结果作为Vector<T,N>不能简单地(合法)将它转换为Polynomial<T,N> 为了达到预期的效果,你需要一些更深入的修改。 您需要一个免费的operator+ ,可提供所需的结果类型和一种方法来检测源自一切的实现Vector<T,N> 让我们建立它。

一个)检测所有Vector<T,N>

对于这一点,你可以从将由空基地优化(EBO)被优化掉空基类派生,这是通过检测std::enable_if

struct VectorBase {};

template< class T, unsigned int N >
class Vector
{
  // ...
};

现在可以检查任何类U如果它衍生自Vector< T, N >std::is_base_of< VectorBase, U >::value 。 要正确是绝对,你需要排除VectorBase本身( !std::is_same< U, VectorBase >::value ),但是这可能是没有必要为您的使用情况。

b)一个实现中,deliveres期望的返回类型。 我们这样做:

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

应改为:

template< class T, unsigned int N >
class Vector
{
    friend Vector< T, N > operator+ ( const Vector< T, N >&, const Vector< T, N >& );
};

对于一般情况。 但是,你需要一个特殊的返回类型可以在以后成为Polynomial<T,N>那么:

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)提供的operator+调用add和由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 );
}

减去一些小的拼写错误(我没有测试过),这种策略应该为你工作。



文章来源: C++ Dynamically detect class of parameter and cast thereto