Do concepts improve deducing this?

published at 04.06.2026 17:22 by Jens Weller
Save to Instapaper Pocket

Last weeks post showed how ref qualifiers led to deducing this. Today I want to look at how concepts can help deducing this to achieve the feature set of ref qualifiers.

Now, and not surprising for C++ folks, there is different ways to achieve the same thing in C++. Especially when one wants to achieve something like an rvalue only callable member function or other specific goals. Which brings up multiple ways to do things, and which one may be the best depends on your viewing angle. This includes the standard you are on, what is supported by your compiler and/or coding standard today and whats best in the context of being also understood by your coworkers. The shortest does not have to be best - for some folks a solution with shorter compilation times might be favorable, while others will favor readibility and/or reusability.

Before I go into concepts and deducing this, lets take a look at how to do this without concepts. One feedback to last weeks post was that one can use =delete also with deducing this, you just need to delete the template specialization of your choice! Its something that is easy to look up if you don't do that every day. But I do wonder if that is truely better then doing the same with a ref qualifier. The template specialization will be more code, and for the reader only at the end its clear what it does. You've read the whole line only to learn that this is a deleted member function. Though you could also only specialize a member function for the rvalue case, and achieve the goal of only supporting rvalues for this function this way.

Last weeks post had one issue with deducing this left: its not able to provide an rvalue only overload on its own - at least with out specialization, while ref qualifiers can do this out of the box. And they do it with less code in an easier readable way. If said function is only rvalue based like the fluent interface setter functions, that might be the best and shortest way to achieve this. And its going to work also if you're not yet on C++23. Though when one combines deducing this with other C++ features, one can achieve the same. Concepts is one way, you also could choose to use a static_assert(!std::is_rvalue_reference<Self>, "your error message");. This way you have control over what your API users will see as an error message if they are calling the function from the wrong context. When only part of your code inside said member function needs to be different, if constexpr is the way to go. 

Using a concept is on the other hand the only way to achieve reusability. You can encode part of your message in the concept name. And doing so is trivial:

template< class T>
concept deducing_this_rvalue_only = std::is_rvalue_reference_v< T >;

This concept is not deducing this specific, and you could choose to use requires to constraint the member function it self. But the name is good for the context to make folks understand the error message better. It could even be longer and more specific.

Reusing the logger example from the first post, this now refactors to this:

Logger&& setLogLevel(this deducing_this_rvalue_only auto&& self,loglevel ll){self.level=ll;return std::move(&self);}

I still got to get used to see four words for one parameter, and you can see the other things that deducing this brings with it. You don't have access to this in the member function, so this is replaced by self. This is also true for the implicit calls to this like member variables and functions. Refactoring to deducing this is more then just changing the function signature. You can look at the full code example to play around with on godbolt.

As I said in the second paragraph, I'm not sure if that is the right solution for you. One certainly can do more with the concept, yet in this context all one checks for is the type containing the member function and specifically its objects instance state. I don't think its the right place to check for other constraints needed for your type, static_asserts after the class/struct declaration are much better for this. The concept allows in this context for what other wise specialization + delete would do. Its one more way to achieve a goal. Specialization of the member function will also help you if you need to react different to the other possible contexts.

So if you want to fully replace ref qualifiers, you can do so with deducing this by either specialization, using a static_assert or defining a reusable concept. Though its up to you if and how you should do that. If readiblity and shortness of code plays a role for you, choosing ref qualifiers in some edge cases is still valid even with C++23.

 

 

Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!