C++ Gems: ref-qualifiers

VC++ 2014 is finally supporting ref-qualifiers, maybe a lesser know feature in C++11 that goes hand in hand with rvalue references. In this post I will explain what ref-qualifiers are and why they are important.

But before talking about ref-qualifiers let’s talk about the well known cv-qualifiers.

cv-qualifiers

Let’s take the following example of a type foo that has two overloaded methods, one const and one not const.

The following code prints either “test” or “test const” depending on whether the object function test() is called on is const or not.

Notice that the const/volatile specification is not a constrain on the function, but on the implied this parameter. A const function can freely modify state or call non-const methods, but not state or non-const methods that belong to the object referred by this.

Let’s consider a second example where he have a Widget contained within a bar. The bar has methods to return the internal state. If the object is const, the overload resolution picks the const method, if it is non-const it picks the non-const method.

The problem with this code is that in all cases the Widget was copied even though in the last example the Widget owner was an rvalue reference and the object could have been moved.

To fix this problem we can add a new method that returns an rvalue reference. However, the problem now is that we cannot have two overloaded methods, one that returns a lvalue reference and one that returns an rvalue reference. So the best we could do is this:

This fixed the 3rd case with the rvalue reference, but it broke the first object. After calling b1.data() the Widget from b1 was moved to w1.

What’s the solution?

Enter ref-qualifiers

ref-qualifiers are a way to help the compiler decide which function to call when the object is an lvalue or an rvalue. Since the object is passed as an implicit pointer type parameter to the function (pointer this) the ref-qualifiers have been also referred as “rvalue reference for *this”.

ref-qualifiers are specified with & for lvalues and && for rvalues at the end of the function signature after the cv-qualifiers.

The following code now prints “copy”, “copy”, “move” as expected.

One important thing to note is that you cannot mix ref-qualifier and non-ref-qualifier overloads. You must decided over one or another set of overloads. The following is illegal:

The ref-qualifiers help avoiding unnecessary calls/operations on rvalue references which is helpful when may involve large objects. But they are also helpful to avoid making coding mistakes. Here is an example. Consider the following type:

You can write things like this:

Probably the first example is a little bit silly, you don’t do that kind of mistake in real life, but it’s still legal code that executes, and is not right because there’s an rvalue reference on the left side of the assignment operator. The second example is definitely a much realistic example. Sometimes we just type = instead of == in conditional expressions and what the code will do is assigning 42 to temporary, instead of testing their equality.

If we changed the signature of foo’s operator= to include a ref-qualifier (as shown below) the compiler would flag immediately both examples above as errors:

VC++ 2014 now flags the following error:

error C2678: binary ‘=’: no operator found which takes a left-hand operand of type ‘foo’ (or there is no acceptable conversion)

Compiler support

See also

Leave a Reply