c++ - std::transform 中的二元运算符,带有 unique_ptr 的 vector

标签 c++ c++11

当应用于 unique_ptr vector 时,我对标准库转换感到困惑。我已经定义了一个二进制仿函数 addScalar,它接受 2 个对 unique_ptr 的常量引用并返回一个对 unique_ptr 的常量引用以避免复制(unique_ptr 禁止这样做)。

然后我尝试在 std::transform 中使用它,但 unique_ptr 似乎根本不可能进行二进制操作,尽管我采取了所有预防措施来避免 unique_ptr 复制...

有人知道如何将 std::transform 与 std::unique_ptr 一起使用吗?还是我必须使用 for 循环遍历 vector 并“手动”执行加法?我也想知道我是否可以使用 unique_ptr<const Scalar>在我的仿函数中。

这是我的类(class):

#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>*’

最佳答案

addScalar 的返回类型将分配给一个unique_ptr<Scalar>所以它不能返回常量引用,因为 unique_ptr没有复制任务。因此,您必须按值返回才能调用移动赋值。

为了避免构造一个新的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;
}

Andrey 制作了一个 good point , 目前尚不清楚这是否根据标准严格允许。我会把它留给语言律师。另见 this answer .

Live demo.

关于c++ - std::transform 中的二元运算符,带有 unique_ptr 的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32904092/

相关文章:

c++ - 自定义排序元组 vector 时出错

c++ - 我怎么知道变量是否可以直接写入二进制文件?

c++ - 如何在 long 变量中保留小时、分钟、秒?

c++ - unique_ptr - 重大改进?

c++ - 我需要#undef 本地#define 吗?有本地定义这样的东西吗?

c++ - 如何在 MPI 部分之外处理 IO 等

c++ - 如何在c++中实现函数超时

c++:错误:在'class std::result_of<void (*(std::unordered_map

algorithm - Topcoder - grafixMask,实现 DFS

c++ - 英特尔 TBB 中的任务延续