Scalar,Vector,Tensor的抽象基类,

时间:2014-07-05 11:28:04

标签: c++ vector

我想设计一个类PrimitiveType,它用作数学实体的抽象类,例如标量,向量,张量等,以将它们存储在std::vector<PrimitiveType *> myVector中,我可以通过它进行迭代。例如,有两个相同大小的矢量,比如myVector1myVector2,我希望能够做类似的事情

for (size_t i = 0; i < myVector1.size(); i++)
     myVector1[i] += myVector2[i];

并且不想关心我是否添加了标量,向量或张量。到目前为止,我想出了

#include <algorithm>
#include <cstddef>
#include <iostream>

template<class T> class Scalar;

template<class T>
class PrimitiveType
{ 
    protected:
        size_t size_;
        T *value_;

    public:
        virtual ~PrimitiveType() = 0;
        PrimitiveType & operator+=(const PrimitiveType &primitiveType) 
        {
            for (size_t i = 0; i < size_; i++)
                value_[i] += primitiveType.value_[i]; 
            return *this;
        }
};

template<class T> PrimitiveType<T>::~PrimitiveType() {};

template<class T>
class Scalar : public PrimitiveType<T>
{
    using PrimitiveType<T>::size_;
    using PrimitiveType<T>::value_;

    public:
        Scalar(T value = 0.0) 
        { 
            size_ = 1; 
            value_ = new T(value); 
        }
        ~Scalar() { delete value_; }
        operator T &() { return *value_; }
};

template<class T>
class Vector : public PrimitiveType<T>
{
    using PrimitiveType<T>::size_;
    using PrimitiveType<T>::value_;

    public:
        Vector(T value = 0.0) 
        { 
            size_ = 3; 
            value_ = new T[size_]; 
            std::fill(value_, size_, value); 
        }
        ~Vector() { delete[] value_; }
        T & operator()(size_t index) { return value_[index]; }
};

int main()
{   
    Scalar<double> s(3.2);
    std::cout << s << std::endl;

    static const size_t size = 3;

    std::vector<PrimitiveType<double> *> p = std::vector<PrimitiveType<double> *>(size);
    for (size_t i = 0; i < size; i++)
    {
        p[i] = new Scalar<double>();
        *(p[i]) += s;
        std::cout << *static_cast<Scalar<double> *>(p[i]) << std::endl;
    }
}

但我不认为这是一个非常干净的解决方案。特别是,

1)我希望能够在子类中使用初始化列表,但是会遇到依赖名称查找的问题,例如

  

错误:'使用PrimitiveType :: size_'不是'Scalar'的非静态数据成员

如何实现Scalar(T value = 0.0) : size_(1) , value_(new T(value)) {}之类的内容?

2)我实际上更愿意将value_设为静态数组,因为我在编译时知道value_ScalarVector的大小{...}当然,这不适用于PrimitiveType,但是,永远不会创建PrimitiveType的实例。

1 个答案:

答案 0 :(得分:2)

编辑:完成编辑,因为其他解决方案无效。

嗯,问题的最简单方法是将存储从主类移动到基类并提供元素的访问器:

template <class C>
class PrimitiveType {
public:
    PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
        if (this->_size() != primitiveType._size()) {
            throw "Incompatible type." ;
        }
        for (size_t i = 0 ; i < this->_size() ; ++i) {
            this->_get(i) += primitiveType._get(i) ;
        }
        return *this ;
    }
protected:
    virtual C& _get (size_t) = 0 ;
    virtual C _get(size_t) const = 0 ;
    virtual size_t _size () const = 0 ;
};

然后在ScalarVector例如:

template <class C>
class Scalar : PrimitiveType <C> {
    C _value ;
public:
    Scalar (C const& c) : _value(c) { }
protected:
    virtual C& _get (size_t) = 0 { return _value ; }
    virtual C _get(size_t) const = 0 { return _value ; }
    virtual size_t _size () const = 0 { return 1 ; }
};

template <class C, int N = 3>
class Vector : PrimitiveType <C> {
    std::array <C, N> _values ;
public:
    Scalar (std::initializer_list <C> l) : _values(l) { }
protected:
    virtual C& _get (size_t i) = 0 { return _values(i) ; }
    virtual C _get(size_t i) const = 0 { return _values(i) ; }
    virtual size_t _size () const = 0 { return _values.size() ; }
};

编辑结束。

关于第一个问题,只需在PrimitiveType中添加一个受保护的构造函数,然后从子类中调用它:

class PrimitiveType {
protected:
    PrimitiveType (/* */) : _values(/* */), /* ... */ { }
};

class Scalar {
public:
    Scalar (/* */) : PrimitiveType(/* */) { }
}

对于第二个问题,添加存储类型作为基本类型的第二个参数模板:

template <class C, class S = std::vector <C>>
class PrimitiveType { /* */ }

template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> { /* */ }

详细示例:

template <class C, class S = std::vector <C>>
class PrimitiveType {
public:
    PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
        /** Same code as yours. **/
    }

protected:
    S _values ;
    PrimitiveType (std::initializer_list <C> l) : _values(l) { }
};

template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> {
public:
    Scalar (C const& c) : PrimitiveType({c}) { }
};