Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent use of const qualifier between declaration and definition

Tags:

c++

gcc

clang

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:

  1. Is this regulated by the standard or is this implementation defined?
  2. Why is the behavior is different between regular and template classes?
  3. Why is there no error or at least a warning that the const qualifier is used inconsistently between the declaration and the definition?
  4. Are there any situation where this could be useful?

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

like image 920
detunized Avatar asked Dec 18 '13 13:12

detunized


People also ask

What is the use of having the const qualifier?

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.

What is the effect of declaring a method to be const?

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.

What is const type qualifier?

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.

What is the use of const keyword in C?

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.


2 Answers

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

like image 101
Shafik Yaghmour Avatar answered Oct 21 '22 23:10

Shafik Yaghmour


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.

like image 31
Kaz Avatar answered Oct 21 '22 23:10

Kaz