I noticed that it's possible to have const
qualifier on a value argument present in the function declaration and then omitted in the definition. That doesn't change the signature of the function. It actually compiles well.
I also noticed that the behavior is different between regular and template classes. Also there's a difference between how it's handled in GCC and Clang.
Consider the following code:
template <typename T> struct A {
void f(const int);
};
template <typename T> void A<T>::f(int x) {
x = 0;
}
struct B {
void f(const int);
};
void B::f(int x) {
x = 0;
}
void f() {
A<float> a;
a.f(0);
B b;
b.f(0);
}
When I compile with GCC I get no errors. With Clang I get:
test.cpp:10:7: error: read-only variable is not assignable
x = 0;
~ ^
test.cpp:26:7: note: in instantiation of member function 'A<float>::f' requested here
a.f(0);
^
GCC took preference of the qualifier at the definition. Clang used the declaration and only for the template class A
.
My questions are:
const
qualifier is used inconsistently between the declaration and the definition?Update:
According to the comments it seems to be a Clang bug. I opened a new ticket.
Update:
The bug is fixed:
Fixed in r203741
We use the const qualifier to declare a variable as constant. That means that we cannot change the value once the variable has been initialized. Using const has a very big benefit. For example, if you have a constant value of the value of PI, you wouldn't like any part of the program to modify that value.
A "const function", denoted with the keyword const after a function declaration, makes it a compiler error for this class function to change a member variable of the class. However, reading of a class variables is okay inside of the function, but writing inside of this function will generate a compiler error.
The const qualifier explicitly declares a data object as something that cannot be changed. Its value is set at initialization. You cannot use const data objects in expressions requiring a modifiable lvalue. For example, a const data object cannot appear on the lefthand side of an assignment statement.
The const keyword allows a programmer to tell the compiler that a particular variable should not be modified after the initial assignment in its declaration.
This behavior is defined by the standard and as far as I can tell gcc
is correct here, if we look at the draft C++ standard section 13.1
Overloadable declarations paragraph 3 says:
[...]-Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called.
and provides this example:
[ Example:
typedef const int cInt;
int f (int);
int f (const int); // redeclaration of f(int)
int f (int) { /* ... */ } // definition of f(int)
int f (cInt) { /* ... */ } // error: redefinition of f(int)
—end example ]
and some details clarifying that that this applies only to the outermost cv qualifiers (emphasis mine):
Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations.123 In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.”
and as far as I can tell this applies to template functions in template classes as well from section 14.8
Function template specializations specifically 14.8.3
Overload resolution which says:
[...]The complete set of candidate functions includes all the synthesized declarations and all of the non-template overloaded functions of the same name. The synthesized declarations are treated like any other functions in the remainder of overload resolution, except as explicitly noted in 13.3.3.144
This is a bug because it prevents legitimate code like:
/* API declaration */
void f(int);
/* Implementation */
void f(const int x) /* my business: x is my local var and I want it const */
{
}
I can't believe anyone would code out of their way to diagnose this as a problem.
Incidentally, GCC, which doesn't complain about this, used to have a warning about this situation. Perhaps it still does:
void f(int func_ptr(void));
void f(int (*func_ptr)(void))
{
}
This is purely a stylistic inconsistency that doesn't serve a purpose, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With