Expression templates and C++11

后端 未结 2 486
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-12 11:28

Let\'s look at one particular benefit of expression templates: ETs can be used to avoid vector-sized temporaries in memory which occur in overloaded operators like:

2条回答
  •  青春惊慌失措
    2020-12-12 12:09

    Here is the corrected version of Paul Preney's code. I have informed the author by email and in comments; I have written an edit, but it has been rejected by unqualified reviewers.

    The error in the original code is that BinaryOp template parameter of math_vector_expr::operator+ is fixed.

    #include 
    #include 
    #include 
    #include 
    #include 
    
    //#define DONT_USE_EXPR_TEMPL
    
    //===========================================================================
    
    template  class math_vector;
    template  struct plus_op;
    
    
    template <
      typename LeftExpr,
      typename BinaryOp,
      typename RightExpr
    >
    class math_vector_expr
    {
      public:
        typedef typename std::remove_reference::type::value_type value_type;
    
        math_vector_expr() = delete;
    
        math_vector_expr(LeftExpr l, RightExpr r) :
          l_(std::forward(l)),
          r_(std::forward(r))
        {
        }
    
        // Prohibit copying...
        math_vector_expr(math_vector_expr const&) = delete;
        math_vector_expr& operator =(math_vector_expr const&) = delete;
    
        // Allow moves...
        math_vector_expr(math_vector_expr&&) = default;
        math_vector_expr& operator =(math_vector_expr&&) = default;
    
        template 
        auto operator +(RE&& re) const ->
          math_vector_expr<
            math_vector_expr const&,
            plus_op,
            decltype(std::forward(re))
          >
        {
          return
            math_vector_expr<
              math_vector_expr const&,
              plus_op,
              decltype(std::forward(re))
            >(*this, std::forward(re))
          ;
        }
    
        auto le() ->
          typename std::add_lvalue_reference::type
          { return l_; }
    
        auto le() const ->
          typename std::add_lvalue_reference<
            typename std::add_const::type
          >::type
          { return l_; }
    
        auto re() ->
          typename std::add_lvalue_reference::type
          { return r_; }
    
        auto re() const ->
          typename std::add_lvalue_reference<
            typename std::add_const::type
          >::type
          { return r_; }
    
        auto operator [](std::size_t index) const ->
          value_type
        {
          return BinaryOp::apply(le()[index], re()[index]);
        }
    
      private:
        LeftExpr l_;
        RightExpr r_;
    };
    
    //===========================================================================
    
    template 
    struct plus_op
    {
      static T apply(T const& a, T const& b)
      {
        return a + b;
      }
    
      static T apply(T&& a, T const& b)
      {
        a += b;
        return std::move(a);
      }
    
      static T apply(T const& a, T&& b)
      {
        b += a;
        return std::move(b);
      }
    
      static T apply(T&& a, T&& b)
      {
        a += b;
        return std::move(a);
      }
    };
    
    //===========================================================================
    
    template 
    class math_vector
    {
      using impl_type = std::array;
    
      public:
        typedef typename impl_type::value_type value_type;
    
        math_vector()
        {
          using namespace std;
          fill(begin(v_), end(v_), impl_type{});
          std::cout << this << ": math_vector()" << endl;
        }
    
        math_vector(math_vector const& mv) noexcept
        {
          using namespace std;
          copy(begin(mv.v_), end(mv.v_), begin(v_));
          std::cout << this << ": math_vector(copy: " << &mv << ")" << endl;
        }
    
        math_vector(math_vector&& mv) noexcept
        {
          using namespace std;
          move(begin(mv.v_), end(mv.v_), begin(v_));
          std::cout << this << ": math_vector(move: " << &mv << ")" << endl;
        }
    
        math_vector(std::initializer_list l)
        {
          using namespace std;
          copy(begin(l), end(l), begin(v_));
          std::cout << this << ": math_vector(initlist)" << endl;
        }
    
        math_vector& operator =(math_vector const& mv) noexcept
        {
          using namespace std;
          copy(begin(mv.v_), end(mv.v_), begin(v_));
          std::cout << this << ": math_vector op =(copy: " << &mv << ")" << endl;
          return *this;
        }
    
        math_vector& operator =(math_vector&& mv) noexcept
        {
          using namespace std;
          move(begin(mv.v_), end(mv.v_), begin(v_));
          std::cout << this << ": math_vector op =(move: " << &mv << ")" << endl;
          return *this;
        }
    
        ~math_vector()
        {
          using namespace std;
          std::cout << this << ": ~math_vector()" << endl;
        }
    
        void swap(math_vector& mv)
        {
          using namespace std;
          for (std::size_t i = 0; i value_type const&
        {
          return v_[index];
        }
    
        auto operator [](std::size_t index)
          -> value_type&
        {
          return v_[index];
        }
    
        math_vector& operator +=(math_vector const& b)
        {
          for (std::size_t i = 0; i
        math_vector(math_vector_expr&& mve)
        {
          for (std::size_t i = 0; i < N; ++i)
            v_[i] = mve[i];
          std::cout << this << ": math_vector(expr: " << &mve << ")" << std::endl;
        }
    
        template 
        math_vector& operator =(RightExpr&& re)
        {
          for (std::size_t i = 0; i
        math_vector& operator +=(RightExpr&& re)
        {
          for (std::size_t i = 0; i
        auto operator +(RightExpr&& re) const ->
          math_vector_expr<
            math_vector const&,
            plus_op,
            decltype(std::forward(re))
          >
        {
          return
            math_vector_expr<
              math_vector const&,
              plus_op,
              decltype(std::forward(re))
            >(
              *this,
              std::forward(re)
            )
          ;
        }
    
      #endif // #ifndef DONT_USE_EXPR_TEMPL
    
      private:
        impl_type v_;
    };
    
    //===========================================================================
    
    template 
    inline void swap(math_vector& a, math_vector& b)
    {
      a.swap(b);
    }
    
    //===========================================================================
    
    #ifdef DONT_USE_EXPR_TEMPL
    
    template 
    inline math_vector operator +(
      math_vector const& a,
      math_vector const& b
    )
    {
      math_vector retval(a);
      retval += b;
      return retval;
    }
    
    template 
    inline math_vector operator +(
      math_vector&& a,
      math_vector const& b
    )
    {
      a += b;
      return std::move(a);
    }
    
    template 
    inline math_vector operator +(
      math_vector const& a,
      math_vector&& b
    )
    {
      b += a;
      return std::move(b);
    }
    
    template 
    inline math_vector operator +(
      math_vector&& a,
      math_vector&& b
    )
    {
      a += std::move(b);
      return std::move(a);
    }
    
    #endif // #ifdef DONT_USE_EXPR_TEMPL
    
    //===========================================================================
    
    template 
    std::ostream& operator <<(std::ostream& os, math_vector const& mv)
    {
      os << '(';
      for (std::size_t i = 0; i < N; ++i)
        os << mv[i] << ((i+1 != N) ? ',' : ')');
      return os;
    }
    
    //===========================================================================
    
    int main()
    {
      using namespace std;
    
      try
      {
        {
          cout << "CASE 1:\n";
          math_vector<3> a{1.0, 1.1, 1.2};
          math_vector<3> b{2.0, 2.1, 2.2};
          math_vector<3> c{3.0, 3.1, 3.2};
          math_vector<3> d{4.0, 4.1, 4.2};
          math_vector<3> result = a + b + c + d;
          cout << '[' << &result << "]: " << result << "\n";
        }
        cout << endl;
        {
          cout << "CASE 2:\n";
          math_vector<3> result =
            math_vector<3>{1.0, 1.1, 1.2} +
            math_vector<3>{2.0, 2.1, 2.2} +
            math_vector<3>{3.0, 3.1, 3.2} +
            math_vector<3>{4.0, 4.1, 4.2}
          ;
          cout << '[' << &result << "]: " << result << "\n";
        }
      }
      catch (...)
      {
        return 1;
      }
    }
    
    //===========================================================================
    

提交回复
热议问题