函数定义

时间:2015-06-12 08:28:44

标签: c++ const language-lawyer

我想知道C ++如何使用它的const关键字。

我有以下功能定义。单独看起来很疯狂,但效果很好。

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

我知道const的每个位置意味着什么,这个问题不是关于const关键字放置的意义。

我对使用const关键字感到很困惑,因为你可以复制它们。

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

为什么语言允许你这样做?

编辑: 此代码可以在Visual Studio 2013,Visual C ++编译器中编译。我不确定编译器的实际名称。

EDIT2: 所以答案是这是违反标准的。该代码仅使用/Za选项编译。

我投票结束了这个问题。

5 个答案:

答案 0 :(得分:10)

标准中不允许在同一类型说明符序列中明确重复const

[dcl.type] / 2(强调我的)

  

作为一般规则,在声明的完整decl-specifier-seq中最多允许一个类型说明符或   在type-specifier-seq或trailing-type-specifier-seq。

中      

...

     

- const可以与除自身之外的任何类型说明符组合。

有人可能会认为这可以从以下引用中获得(由@davidhigh找到):

[dcl.type.cv] / 1

  

有两个cv限定符,const和volatile。每个cv-qualifier在cv-qualifier-seq中最多只出现一次。如果cv-qualifier出现在decl-specifier-seq中,则声明的init-declarator-list不应为空。 [注意:3.9.3和8.3.5描述了cv限定符如何影响对象和函数类型。 - 尾注] 忽略冗余cv资格。 [注意:例如,这些可以由typedef引入。 - 结束说明]

但是,此规则允许通过模板或const中的替换产生typedef重复,而不是程序员明确键入的重复。

举一个例子:

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

前四个const都适用于int,违反了上面发布的规则。

接下来的两个const适用于指针,并且由同一规则无效。

最后两个const甚至不是Get声明的一部分。它们将应用于解析器下一步找到的任何内容,通过与上述相同的规则或其他C ++语法规则变为无效。

VS2013可以使用语言扩展编译此类代码,但这不是标准行为。 gcc 5.1.0clang 3.5.1都会拒绝编译您的代码,并且都会提供合理的诊断。

答案 1 :(得分:3)

重新

  

为什么语言允许您这样做?”

它没有。提供的代码是不是真正的代码。 E.g。

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

(第一个示例)不会使用任何符合标准的编译器进行编译,原因有两个:

  • 不允许开头的多个constint)。
  • 最后的const是语法错误。

Standardeese的第一点:C ++11§7.1.6/ 2,

  

const可以与除自身之外的任何类型说明符组合使用。

答案 2 :(得分:1)

为什么呢?因为标准是这样说的。以下是[dcl.type.cv]的摘录,其中正好说明了这一点(强调我的):

  

有两个cv限定符,const和volatile。每个cv-qualifier在cv-qualifier-seq中最多只出现一次。   如果cv-qualifier出现在decl-specifier-seq中,则声明的init-declarator-list应为   不是空的。 [注意:3.9.3和8.3.5描述了cv限定符如何影响对象和函数类型。 - 结束说明]   忽略冗余cv资格。 [注意:例如,这些可以由typedef引入。 - 结束   注意]

例如,这在模板中很有意义。如果模板参数推导为const,则很容易发生另一个const被添加到某个地方。

编辑:如上所述多次冗余,我的上述答案具有误导性,因为它不符合此条件。它被[dcl.type]中的规则所反对,该规则明确禁止明确键入const限定符(请参阅@TartanLlama在其答案中的精细注释)。

编辑2 :规则的应用每个人似乎都同意状态:第一个冗余的const是不允许的,如果它们仍然应该在某个地方发生,则会被忽略。

但是,这需要标准报价的优先级。

如果没有,人们也可以想到这样一个顺序:首先删除多余的const,然后才应用不允许多个const的规则(当然,这会导致后一条规则本身就是多余的。)

在这种情况下,显然,引用显示了它的解释方式。但是,作为迂腐,它不必像这样解释 - 除非标准引号中有某种形式的优先权。

答案 3 :(得分:0)

此功能声明(及其他)

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

将无法编译,因为根据C ++标准(7.1.6类型说明符,#2)

  

- const可以与任何类型说明符组合,除了它本身

和(7.1.6.1 cv-qualifiers)

  

1有两个cv限定符,const和volatile。每个cv-qualifier   在cvqualifier- seq中最多出现一次

在此声明中,例如限定符const与其自身结合

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

此外,最后一个限定符放在错误的位置。:)

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

在皮带上应该有

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

或者在此声明中(如果正确放置cv-qualifier序列)至少cv-qualifier序列具有多个const限定符

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

与C中的C ++相反,您可以在声明中组合多个限定符。简单地忽略冗余限定符。例如

const long const long const int const x = 10;

相当于

const long long int x = 10;

但是在C ++中,这个声明不会编译。

答案 4 :(得分:0)

两个单独的问题。

  1. 默认情况下,MSVC会针对重复的限定符而不是错误发出警告(C4114)。该标准允许这样做,因为所需要的只是一条诊断消息,并且警告满足了这一要求。

  2. 最终const只有当它们实际上是后续声明的一部分时才会编译。例如:

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

    这实际上是

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

    这是"好的"模拟重复的限定符部分。