Quadruple "const" in function definition

346 views Asked by At

I am wondering about how C++ uses its const keyword.

I have the following function definition. Which alone looks quite insane, but works just fine.

const int const * const Get(){ return new int(1); } const

I am aware of what each placement of the const means, this question isn't about the meaning of the placement of the const keyword.

I am quite confused by the use of the const keywords, because you can duplicate them.

const int const const * const Get(){ return new int(1); } const

// or even

const const int const const * const const Get(){ return new int(1); } const const

// or even yet

const const const int const const const * const const const Get(){ return new int(1); } const const const

Why does the language allow you to do this?

EDIT: This code can be compiled in Visual Studio 2013, Visual C++ compiler. I am not sure about the actual name of the compiler.

EDIT2: So the answer is that this is against the standard. The code only compiles wihout using /Za option.

I am voting to close the question.

5

There are 5 answers

3
davidhigh On

Why? Because the standard says so. Here is an excerpt from [dcl.type.cv] which states exactly this (emphasis mine) :

There are two cv-qualifiers, const and volatile. Each cv-qualifier shall appear at most once in a cv-qualifier-seq. If a cv-qualifier appears in a decl-specifier-seq, the init-declarator-list of the declaration shall not be empty. [ Note: 3.9.3 and 8.3.5 describe how cv-qualifiers affect object and function types. — end note ] Redundant cv-qualifications are ignored. [ Note: For example, these could be introduced by typedefs. — end note ]

This makes sense in templates, for example. If the template parameter is deduced as const, it can easily happen that another const is added somewehere.


EDIT: as noted several times and redundantly, my above answer is misleading in that it does not qualify here. It is opposed by the rule in [dcl.type] which explicitly disallows explicitly typed const qualifiers (see the fine comment by @TartanLlama in his answer).


EDIT 2: the application of the rule everyone seems to agree on states: first redundant consts are disallowed, and if they still should somewhere occur they are ignored.

This, however, requires a priority of the standard quotes.

Without, one could also think of an order like: first remove redundant consts, and only then apply the rule that multiple consts are not allowed (which, of course, would render the latter rule itself redundant).

In this case, obviously, the quote shows how it is meant to be interpreted. But, being pedantic, it does not have to be interpreted like this -- unless there is some form of priority in the standard quotes.

6
TartanLlama On

Explicitly repeating const in the same type specifier sequence is disallowed in the standard.

[dcl.type]/2 (emphasis mine)

As a general rule, at most one type-specifier is allowed in the complete decl-specifier-seq of a declaration or in a type-specifier-seq or trailing-type-specifier-seq.

...

const can be combined with any type specifier except itself.

One might think that this is allowed from the following quote (found by @davidhigh):

[dcl.type.cv]/1

There are two cv-qualifiers, const and volatile. Each cv-qualifier shall appear at most once in a cv-qualifier-seq. If a cv-qualifier appears in a decl-specifier-seq, the init-declarator-list of the declaration shall not be empty. [ Note: 3.9.3 and 8.3.5 describe how cv-qualifiers affect object and function types. — end note ] Redundant cv-qualifications are ignored. [ Note: For example, these could be introduced by typedefs. — end note ]

However, this rule is to allow const duplications which arise through substitution in templates or typedefs, not those explicitly typed by the programmer.

Taking one of your examples:

const const int const const * const const Get(){ return new int(1); } const const

The first four consts all apply to the int, breaking the rule posted above.

The next two consts apply to the pointer and are invalid by the same rule.

The final two consts are not even part of the declaration for Get. They will be applied to whatever the parser finds next, becoming invalid by either the same rules as above, or by other C++ syntax rules.

VS2013 may compile such code using language extensions, but this is not standard behaviour. gcc 5.1.0 and clang 3.5.1 will both refuse to compile your code and both provide a reasonable diagnostic.

3
Cheers and hth. - Alf On

Re

Why does the language allow you to do this?"

it doesn't. The code presented is not real code. E.g.

const int const * const Get(){ return new int(1); } const

(the first example) will not compile with any standard-conforming compiler, for two reasons:

  • The multiple consts at the start (for the int) are not permitted.
  • The const at the end is a syntax error.

Standardeese for the first point: C++11 §7.1.6/2,

const can be combined with any type specifier except itself.

1
Vlad from Moscow On

This function declaration (and others)

const int const * const Get(){ return new int(1); } const;

will not compile because according to the C++ Standard (7.1.6 Type specifiers, #2)

— const can be combined with any type specifier except itself.

and (7.1.6.1 The cv-qualifiers)

1 There are two cv-qualifiers, const and volatile. Each cv-qualifier shall appear at most once in a cvqualifier- seq.

In this declaration for example qualifier const is combined with itself

const int const * const Get(){ return new int(1); } const;
^^^^^     ^^^^^

Moreover the last qualifier is placed in the wrong place.:)

const int const * const Get(){ return new int(1); } const;
                                                    ^^^^^ 

At leats there should be

const int const * const Get() const { return new int(1); };
                              ^^^^^ 

Or in this declaration (if to place the cv-qualifier sequence correctly) at least cv-qualifier sequence has more than one const qualifier

const const int const const * const const Get() const const { return new int(1); };
                                                ^^^^^ ^^^^^

Opposite to C++ in C you may combine several qualifiers in a declaration. The redundant qualifiers are simply ignored. For example

const long const long const int const x = 10;

that is equivalent to

const long long int x = 10;

However in C++ this declaration will not compile.

1
T.C. On

Two separate issues.

  1. By default MSVC issues a warning (C4114) for repeated qualifiers rather than an error. The standard permits this since all that's required is a diagnostic message, and a warning satisfies this requirement.

  2. The final consts compile only when they are actually part of a subsequent declaration. For instance:

    const const int const const * const const Get(){ return new int(1); } const const
    
    int main() {}
    

    This is actually

    const const int const const * const const Get(){ return new int(1); } 
    
    const const int main() {}
    

    which is "OK" modulo the repeated qualifiers part.