11

I have recently learned about r-value references. In order to more thoroughly experiment I decided to write a simple DenseMatrix class. My question is is it possible to write any function ( Transpose for this example ) such that for auto A = B.Transpose() separate matrix is returned, but for auto A = (B + C).Transpose() the result of the Transpose is calculated in place?

Hen3
  • 175
  • 8

1 Answers1

16

Yes, you can overload the Transpose member function on the ref-qualification of the object it's being called on:

class DenseMatrix {
 
  DenseMatrix Transpose() const & {  // #1 called on l-values
     auto copy = *this;
     // transpose copy
     return copy;
  }

  DenseMatrix&& Transpose() && {  // #2 called on r-values
     // transpose *this
     return std::move(*this);
  }
};

So you get the result:

B.Transpose();        // calls #1
(B + C).Transpose();  // calls #2

Here's a demo.

Note that you could implement the l-value overload in terms of the r-value overload, like this:

DenseMatrix Transpose() const & {  
  auto copy = *this;
  return std::move(copy).Transpose();
}

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • 3
    Why not `DenseMatrix&& Transpose() &&`? I.e. modifying an r-value in-place. – Maxim Egorushkin Jul 17 '20 at 17:05
  • 1
    @MaximEgorushkin I thought of that, but it feels like copy elision would take care of that. I'm not sure though. Edited anyway, since it can't hurt at least. – cigien Jul 17 '20 at 17:06
  • 2
    @cigien `this` is a hidden function argument, and returning a function argument prevents return-value optimization and because `this` is not an object with automatic storage duration here. See https://en.cppreference.com/w/cpp/language/copy_elision : _In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization"._ – Maxim Egorushkin Jul 17 '20 at 17:08
  • @MaximEgorushkin Aah, ok, that makes sense, thanks. It could still be optimized, but it's not guaranteed to. – cigien Jul 17 '20 at 17:08
  • Why there is `&&` after #2 `Transpose()`? I am unfamiliar with this syntax – Piotr Barejko Jul 17 '20 at 17:15
  • 1
    It's the syntax that constrains the function to be called on r-values. In fact this syntax was introduced in c++11 to achieve exactly the effect you're looking for :) – cigien Jul 17 '20 at 17:16
  • @cigien where is this documented? I am googling and I can't find it. – Piotr Barejko Jul 17 '20 at 17:20
  • 2
    @bar3 https://en.cppreference.com/w/cpp/language/member_functions#ref-qualified_member_functions – Maxim Egorushkin Jul 17 '20 at 17:21
  • For a somewhat exhaustive general Q&A on ref-qualifiers, see [What does the & (ampersand) at the end of member function signature mean?](https://stackoverflow.com/questions/47002799/what-does-the-ampersand-at-the-end-of-member-function-signature-mean/47003980#47003980). – dfrib Jul 19 '20 at 21:57