函数定义中的四重"const"

Quadruple "const" in function definition

本文关键字:四重 const 定义 函数      更新时间:2023-10-16

我想知道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++编译器中编译。我不确定编译器的实际名称。

编辑2:所以答案是这违背了标准。该代码仅使用/Za选项进行编译。

我投票结束这个问题。

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

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

作为一般规则,在声明的完整 decl-specifier-seq 中最多允许使用一个类型说明符或 在类型说明符序列或尾随类型说明符序列中。

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

有人可能会认为这是允许从以下引用(由@davidhigh找到的):

[dcl.type.cv]/1

有两个 cv 限定符,const 和 volatile。每个 cv 限定符在 cv 限定符序列中最多出现一次。如果 cv 限定符出现在 decl-specifier-seq 中,则声明的 init-declarator-list 不应为空。[注:3.9.3和8.3.5描述了cv限定符如何影响对象和函数类型。多余的简历资格将被忽略。[ 注意:例如,这些可以通过 typedefs 引入。

但是,此规则允许通过替换模板或typedef而不是程序员显式键入的模板或而引起的const重复。

举个例子:

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

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

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

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

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

Re

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

其实不然。呈现的代码不是真正的代码。例如

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

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

  • 不允许在开头(对于int)使用多个const
  • 末尾的const是语法错误。

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

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

为什么?因为标准是这么说的。以下是[dcl.type.cv]的摘录,其中确切地指出了这一点(强调我的):

有两个 cv 限定符,const 和 volatile。每个 cv 限定符在 cv 限定符序列中最多出现一次。 如果 cv 限定符出现在 decl-specifier-seq 中,则声明的 init-declarator-list 应 不为空。[注:3.9.3和8.3.5描述了cv限定符如何影响对象和函数类型。 多余的简历资格将被忽略。[注意:例如,这些可以通过typedefs引入。 注]

例如,这在模板中是有意义的。如果模板参数推导为 const ,则很容易在某处添加另一个常量。


编辑:正如多次和冗余指出的那样,我的上述答案具有误导性,因为它不符合此处的条件。[dcl.type] 中的规则反对它,该规则明确不允许显式键入const限定符(请参阅@TartanLlama在他的回答中的精美注释)。


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

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

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

在这种情况下,显然,引用显示了它是如何解释的。但是,由于迂腐,它不必这样解释——除非标准引号中有某种形式的优先级。

两个独立的问题。

  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() {}
    

    这是"OK"模重复限定符部分。

此函数声明(和其他)

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

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

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

和(7.1.6.1 简历限定符)

1 有两个 cv 限定符,常量和易失性。每个简历限定符 在 CV限定符中最多出现一次 - 序列。

例如,在此声明中,限定符 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 限定符序列)至少 cv 限定符序列具有多个 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++此声明将不会编译。