Logo

Blog


Understanding the role of cv-qualifiers in function parameters

In today's post, I will continue where I left off with last month's post C++ top-level qualifiers explained. This time, I will focus on function parameters.

Let's use the code of last month's blog post:

1
2
3
4
5
char              robert{};   A 
const char        amy{};      B 
const char*       alfred{};   C 
char* const       linda{};    D 
const char* const melissa{};  E 

Suppose you want to write a function Fun with overloads this time. You could come up with these function prototypes:

1
2
3
4
5
void Fun(char);               F 
void Fun(const char);         G 
void Fun(const char*);        H 
void Fun(char* const);        I 
void Fun(const char* const);  J 

The same I established for variables last time is also true for parameters. There are two different forms of const. Using last month's pseudo-code, the code would be:

1
2
3
4
5
void Fun(char);                                        F 
void Fun(const_by_user_request char);                  G 
void Fun(read_only_data char*);                        H 
void Fun(char* const_by_user_request);                 I 
void Fun(read_only_data char* const_by_user_request);  J 

The implications are the same as well. The const_by_user_request isn't as strong as the read_only_data. If you call Fun with robert (A) the compiler will, of course, call F. However, if you make the same call but with amy (|B|) instead, the compiler will still call F. Assuming that you did not provide an implementation for both. Once you do that, the compiler complains without you even calling the function:

1
2
3
4
5
6
error: redefinition of 'Fun'
    6 | void Fun(const char)
      |      ^
note: previous definition is here
    1 | void Fun(char)
      |      ^

Since const_by_user_request isn't preserved, the function signatures of F and G look the same to the compiler. This is okay as long as you only declare them. Still, once you define them (by implementing the functions), the compiler sees two functions with the same signature. Subsequently, H and J are equal to the compiler.

The reasons here are the same as I talked about last time. The const_by_user_request isn't important for the operation. In the const_by_user_request case, the data is copied so the original data remains untouched, while the read_only_data case keeps the protection up.

Please note, inside Fun const_by_user_request plays a role. Inside Fun one cannot alter the parameter, which is a valuable thing.

Summary

You cannot have function overloads based on top-level cv-qualifiers because C++ omits top-level cv-qualifiers in a function's signature.

More to come

In my next post, I'll explain how the top-level qualifiers come into play when you use type-deduction, either with auto or with templates.

Andreas