当应用于unique_ptr的向量时,我对标准库转换感到困惑。我已经定义了一个二元仿函数addScalar,它对unique_ptr采用2个const引用,并将一个const引用返回给unique_ptr,以避免复制(禁止使用unique_ptr)。
然后我尝试在std :: transform中使用它,但似乎不可能对unique_ptr进行二进制操作,尽管我采取了所有预防措施来避免unique_ptr复制......
有没有人知道如何使用std :: transform和std :: unique_ptr?或者我是否有义务使用for循环遍历向量并执行添加&#34;手动&#34; ?我也想知道我是否可以在我的仿函数中使用unique_ptr<const Scalar>
。
这是我的班级:
#include "space.h"
#include "scalar.h"
#include <vector>
#include <algorithm>
#include <memory>
using std::vector;
using std::ostream;
using std::unique_ptr;
class addScalar
{
public:
unique_ptr<Scalar> const& operator()(unique_ptr<Scalar> const& scal1, unique_ptr<Scalar> const& scal2)
{
*scal1 += *scal2;
return scal1;
};
};
class Tensor4D
{
public:
Tensor4D(Space& space_in, int ncomp);
Tensor4D(const Tensor4D& tens);
Tensor4D& operator=(const Tensor4D& tens);
size_t size() const {return comp.size();};
~Tensor4D();
protected:
Space* const space;
vector<unique_ptr<Scalar>> comp;
public:
Tensor4D& operator+=(const Tensor4D& tens);
};
这里是operator + =:
的实现Tensor4D& Tensor4D::operator+=(const Tensor4D& tens)
{
assert(comp.size() == tens.comp.size());
transform(tens.comp.begin(), tens.comp.end(), comp.begin(), tens.comp.begin(), addScalar());
return *this;
}
我得到以下丑陋的编译器错误:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation) [with _IIter1 = __gnu_cxx::__normal_iterator<const std::unique_ptr<Scalar>*, std::vector<std::unique_ptr<Scalar> > >; _IIter2 = __gnu_cxx::__normal_iterator<std::unique_ptr<Scalar>*, std::vector<std::unique_ptr<Scalar> > >; _OIter = __gnu_cxx::__normal_iterator<const std::unique_ptr<Scalar>*, std::vector<std::unique_ptr<Scalar> > >; _BinaryOperation = addScalar]’:
tensor4D.C:44:94: required from here
/usr/include/c++/4.8/bits/stl_algo.h:4965:12: error: no match for ‘operator=’ (operand types are ‘const std::unique_ptr<Scalar>’ and ‘const std::unique_ptr<Scalar>’)
*__result = __binary_op(*__first1, *__first2);
^
/usr/include/c++/4.8/bits/stl_algo.h:4965:12: note: candidates are:
In file included from /usr/include/c++/4.8/memory:81:0,
from /home/gmartinon/Kadath/C++/Include/scalar.h:27,
from tensor4D.h:5,
from tensor4D.C:1:
/usr/include/c++/4.8/bits/unique_ptr.h:190:7: note: std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = Scalar; _Dp = std::default_delete<Scalar>]
operator=(unique_ptr&& __u) noexcept
^
/usr/include/c++/4.8/bits/unique_ptr.h:190:7: note: no known conversion for argument 1 from ‘const std::unique_ptr<Scalar>’ to ‘std::unique_ptr<Scalar>&&’
/usr/include/c++/4.8/bits/unique_ptr.h:203:2: note: template<class _Up, class _Ep> typename std::enable_if<std::__and_<std::is_convertible<typename std::unique_ptr<_Up, _Ep>::pointer, typename std::unique_ptr<_Tp, _Dp>::_Pointer::type>, std::__not_<std::is_array<_Up> > >::value, std::unique_ptr<_Tp, _Dp>&>::type std::unique_ptr<_Tp, _Dp>::operator=(std::unique_ptr<_Up, _Ep>&&) [with _Up = _Up; _Ep = _Ep; _Tp = Scalar; _Dp = std::default_delete<Scalar>]
operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
^
/usr/include/c++/4.8/bits/unique_ptr.h:203:2: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from tensor4D.h:8,
from tensor4D.C:1:
/usr/include/c++/4.8/bits/stl_algo.h:4965:12: note: types ‘std::unique_ptr<_Tp, _Dp>’ and ‘const std::unique_ptr<Scalar>’ have incompatible cv-qualifiers
*__result = __binary_op(*__first1, *__first2);
^
In file included from /usr/include/c++/4.8/memory:81:0,
from /home/gmartinon/Kadath/C++/Include/scalar.h:27,
from tensor4D.h:5,
from tensor4D.C:1:
/usr/include/c++/4.8/bits/unique_ptr.h:211:7: note: std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(std::nullptr_t) [with _Tp = Scalar; _Dp = std::default_delete<Scalar>; std::nullptr_t = std::nullptr_t]
operator=(nullptr_t) noexcept
^
/usr/include/c++/4.8/bits/unique_ptr.h:211:7: note: no known conversion for argument 1 from ‘const std::unique_ptr<Scalar>’ to ‘std::nullptr_t’
/usr/include/c++/4.8/bits/unique_ptr.h:274:19: note: std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Scalar; _Dp = std::default_delete<Scalar>] <near match>
unique_ptr& operator=(const unique_ptr&) = delete;
^
/usr/include/c++/4.8/bits/unique_ptr.h:274:19: note: no known conversion for implicit ‘this’ parameter from ‘const std::unique_ptr<Scalar>*’ to ‘std::unique_ptr<Scalar>*’
答案 0 :(得分:1)
std::transform
的C ++标准说:
binary_op不得使任何迭代器无效,包括结尾 迭代器,或修改所涉及范围的任何元素。
最好的方法是根据特定需求实现自己的转换功能。
答案 1 :(得分:1)
addScalar的返回类型将分配给unique_ptr<Scalar>
,因此它不能返回const引用,因为unique_ptr
没有复制赋值。因此,您必须返回by-value来调用移动赋值。
为避免构建新的Scalar
,您可以使用std:move_iterator
移至addScalar
,然后移动分配以覆盖移动的值:
class addScalar
{
public:
unique_ptr<Scalar> operator()(unique_ptr<Scalar> scal1,
unique_ptr<Scalar> const& scal2) {
*scal1 += *scal2;
return scal1;
};
};
Tensor4D& Tensor4D::operator+=(const Tensor4D& tens)
{
assert(comp.size() == tens.comp.size());
transform(make_move_iterator(comp.begin()), make_move_iterator(comp.end()),
tens.comp.begin(), comp.begin(), addScalar());
return *this;
}
安德烈提出good point,目前尚不清楚这是否严格按照标准允许。我会把它留给语言律师。另请参阅this answer。