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?
            Asked
            
        
        
            Active
            
        
            Viewed 189 times
        
    11
            
            
        
        Hen3
        
- 175
 - 8
 
1 Answers
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
 
- 
                    3Why 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
 - 
                    1It'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