我可以使用 std::vector 使用额外的默认参数初始化元素吗?

Can I initialize elements with an additional default-parameter using std::vector?

我目前正在开发我自己的小框架,它具有以下设计模式: 每个对象都继承自 LObject 并有一个父对象,当对象中的某些内容发生变化时,它会通知父对象。 这是一个例子:

class LObject
{
public:
    LObject(LObject* const _pParent = nullptr) :
        _mpParent(_pParent),
        _mChildrenCount(0)
    {
        if(parent() != nullptr)
            _mChildId = parent()->GenerateChildId();
    }

    unsigned int id() const { return _mChildId; }

protected:
    LObject* const parent() const { return _mpParent; }

    unsigned int selfId() const { return -1; }
    unsigned int GenerateChildId() const { return _mChildrenCount++; }

    virtual void ChildChanged(unsigned int _childId)
    {
        if(parent() != nullptr)
            parent()->ChildChanged(id());
    }
    virtual void ChildChanged() const
    {
        if(parent() != nullptr)
            parent()->ChildChanged(id());
    }

private:
    LObject* const _mpParent;
    unsigned int _mChildId;
    mutable unsigned int _mChildrenCount;
};

template <typename T>
class LType : public LObject
{
public:
    /// constructors
    LType(LObject* const _pParent=nullptr) : 
        LObject(_pParent),
        _mValue() 
    {}
    LType(const T& _rcValue, LObject* const _pParent=nullptr) :
        LObject(_pParent),
        _mValue(_rcValue)
    {}

    /// template type
    typedef T size_type;

    /// modify data
    void set(const T& _rcValue, bool _notifyParent=true)
    {
        _mValue = _rcValue; 
        if(_notifyParent) 
            ChildChanged();
    }
    void add(const T& _rcValue, bool _notifyParent=true); // same with +=

    /// get data
    const T& operator()() const; // returns _mValue

    /// operators (modify / get data)
    void operator=(const T& _rcValue); // same as set

private:
    T _mValue;
};

class SomeObject : public LObject
{
public:
    SomeObject(LObject* const _pParent = nullptr) : 
        LObject(_pParent), 
        someInt(this) 
    {}    

    LType<int> someInt;

    virtual void ChildChanged(unsigned int _childId)
    {
        LObject::ChildChanged();

        if(_childId == someInt.id())
            std::cout << "someInt changed!" << std::endl;
    }
};

int main(int argc, char* argv[])
{
    SomeObject obj;
    obj.someInt = 5;

    return 0;
}

输出:someInt 改变了!

现在我想实现一个容器 class,它应该像这样工作:

class SomeOtherObject : public LObject
{
public:
    SomeOtherObject (LObject* const _pParent = nullptr) : 
        LObject(_pParent), 
        someContainer(this) 
    {}   

    LContainer<LType<int>> someContainer;

    virtual void ChildChanged(unsigned int _childId)
    {
        LObject::ChildChanged();

        if(_childId == someContainer.id())
            std::cout << "someContainer changed!" << std::endl;
        if(_childId == someContainer[0].id())
            std::cout << "someContainer[0] changed!" << std::endl;
    }
};
int main(int argc, char* argv[])
{
    SomeOtherObject obj2;
    obj.someContainer.push_back(5);
    obj.someContainer[0].set(32);

    return 0;
}

Depending on the implementation the output should be: 
someContainer changed!
someContainer[0] changed!
or 
someContainer changed!
someContainer changed!

(目前我不关心容器的元素是容器的子元素还是它们与容器有相同的父元素。)

因此,如您所见,我希望容器像 std::vector 一样工作,唯一的区别是,在其中创建的对象(使用 push_back 或插入)知道它们的父对象,并且容器知道它的父级。 (也许我什至不关心知道它是父容器的容器,但我认为这是强制性的) 在最好的情况下,我只想使用 std::vector.

我没有找到任何关于 cplusplus 参考中 std::vector::push_back 参数列表末尾传递的默认值等功能的线索。 所以我的问题:

我想要一个容器 class 用于我的小框架,尽可能少地实现 STL 中现有的所有方法。

我想这样实现(如果可能的话)

class LContainer : public std::vector, public LObject
{
    LContainer(LObject* const _pParent) :
        LObject(_pParent)
    {
        std::vector::addValuesWithDefaultParameter(parent()); // If something like that is available)
    }
};

编辑:这就是我解决问题的方法。 我从 LObject 和 std::vector 继承并重新实现了几个向向量添加内容的函数。 注意:私有继承用于防止用户输入obj.container.std::vector::push_back(element);

/// LContainer.h
template <typename T>
class LContainer : public LObject, std::vector<T>
{
public:
    LContainer(LObject* const _pParent=nullptr);
    LContainer(unsigned int _startSize, LObject* const _pParent=nullptr);
    LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent=nullptr);

    /// Iterators
    using std::vector<T>::begin;
    using std::vector<T>::end;
    using std::vector<T>::rbegin;
    using std::vector<T>::rend;
    using std::vector<T>::cbegin;
    using std::vector<T>::cend;
    using std::vector<T>::crbegin;
    using std::vector<T>::crend;

    /// Capacity
    using std::vector<T>::size;
    using std::vector<T>::max_size;
    void resize(unsigned int _newSize, const T& _rcValue);
    using std::vector<T>::capacity;
    using std::vector<T>::empty;
    using std::vector<T>::reserve;
    using std::vector<T>::shrink_to_fit;

    /// Element access
    using std::vector<T>::operator [];
    using std::vector<T>::at;
    using std::vector<T>::front;
    using std::vector<T>::back;

    /// add elements
    void assign(unsigned int _count, const T& _rcValue);
    void push_back(const T& _rcValue);
    using std::vector<T>::pop_back;
    void insert(unsigned int _position, const T& _rcValue);
    void insert(unsigned int _position, unsigned int _count, const T& _rcValue);
    using std::vector<T>::erase;
    using std::vector<T>::swap;
    using std::vector<T>::clear;
    using std::vector<T>::emplace;
    using std::vector<T>::emplace_back;

    /// Allocator
    using std::vector<T>::get_allocator;

private:
    T _mElementDummy;
};

/// LContainer.inl file
template <typename T>
LContainer<T>::LContainer(LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{
    while(std::vector::size() < _startSize)
        std::vector::push_back(_mElementDummy);
}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{
    _mElementDummy = _rcValue;

    while(std::vector::size() < _startSize)
        std::vector::push_back(_mElementDummy);
}

template <typename T>
void LContainer<T>::resize(unsigned int _newSize, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::resize(_mElementDummy, _mElementDummy);
}

template <typename T>
void LContainer<T>::assign(unsigned int _count, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::assign(_count, _mElementDummy);
}
template <typename T>
void LContainer<T>::push_back(const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::push_back(_mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::insert(_position, _mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, unsigned int _count, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::insert(_position, _count, _mElementDummy);
}

std::vector::push_back 没有能力接受额外的参数。

我的建议:

  1. 使用组合而不是从 std::vector 继承来定义 LContainer

    class LContainer : public LObject
    {
        LContainer(LObject* const _pParent) : LObject(_pParent)
        {
        }
    
        // Member variable 
        std::vector<LObject*> containedObjects_;
    };
    
  2. LContainer中添加一个函数来添加对象。在这个函数中,使用std::vector::push_back,然后做必要的附加处理。

    class LContainer : public LObject
    {
        LContainer(LObject* const _pParent) : LObject(_pParent)
        {
        }
    
        void addObject(LObject* object)
        {
           containedObjects_.push_back(object);
    
           // Do the additional processing.
           // ...
           //
        }
    
        // Member variable 
        std::vector<LObject*> containedObjects_;
    };
    

我找到的最佳解决方案是从 LObject 和 std::vector 继承并重新实现几个向向量添加内容的函数。

std::vector 中的功能是通过关键字 using 获取的。

注意:私有继承用于防止用户输入obj.container.std::vector::push_back(element);

/// LContainer.h
template <typename T>
class LContainer : public LObject, std::vector<T>
{
public:
    LContainer(LObject* const _pParent=nullptr);
    LContainer(unsigned int _startSize, LObject* const _pParent=nullptr);
    LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent=nullptr);

    /// Iterators
    using std::vector<T>::begin;
    using std::vector<T>::end;
    using std::vector<T>::rbegin;
    using std::vector<T>::rend;
    using std::vector<T>::cbegin;
    using std::vector<T>::cend;
    using std::vector<T>::crbegin;
    using std::vector<T>::crend;

    /// Capacity
    using std::vector<T>::size;
    using std::vector<T>::max_size;
    void resize(unsigned int _newSize, const T& _rcValue);
    using std::vector<T>::capacity;
    using std::vector<T>::empty;
    using std::vector<T>::reserve;
    using std::vector<T>::shrink_to_fit;

    /// Element access
    using std::vector<T>::operator [];
    using std::vector<T>::at;
    using std::vector<T>::front;
    using std::vector<T>::back;

    /// add elements
    void assign(unsigned int _count, const T& _rcValue);
    void push_back(const T& _rcValue);
    using std::vector<T>::pop_back;
    void insert(unsigned int _position, const T& _rcValue);
    void insert(unsigned int _position, unsigned int _count, const T& _rcValue);
    using std::vector<T>::erase;
    using std::vector<T>::swap;
    using std::vector<T>::clear;
    using std::vector<T>::emplace;
    using std::vector<T>::emplace_back;

    /// Allocator
    using std::vector<T>::get_allocator;

private:
    T _mElementDummy;
};

/// LContainer.inl file
template <typename T>
LContainer<T>::LContainer(LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{
    while(std::vector::size() < _startSize)
        std::vector::push_back(_mElementDummy);
}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent) :
    LObject(_pParent),
    std::vector<T>(),
    _mElementDummy(_pParent)
{
    _mElementDummy = _rcValue;

    while(this->size() < _startSize)
        std::vector::push_back(_mElementDummy);
}

template <typename T>
void LContainer<T>::resize(unsigned int _newSize, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::resize(_mElementDummy, _mElementDummy);
}

template <typename T>
void LContainer<T>::assign(unsigned int _count, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::assign(_count, _mElementDummy);
}
template <typename T>
void LContainer<T>::push_back(const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::push_back(_mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::insert(_position, _mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, unsigned int _count, const T& _rcValue)
{
    _mElementDummy = _rcValue;
    std::vector::insert(_position, _count, _mElementDummy);
}