函数定义中的 "const" 增加到四个

4

我想知道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选项的情况下,代码才能编译。
我投票关闭问题。

3
“为什么语言允许你这样做?”这种说法是不正确的,事实上语言并不允许这样做。 - Cheers and hth. - Alf
1
−1 不是真正的代码。 - Cheers and hth. - Alf
2
@Python- 编译并不能证明代码符合标准。你是否记得告诉编译器不要使用任何扩展?你确定编译器符合标准吗? - eerorika
1
我投票关闭这个问题,因为它不是一个真正的问题。问题中所谓的事实并不属实。 - Cheers and hth. - Alf
1
@Python- 关于“它可以在Visual Studio 2013编译”的问题,实际上,没有任何一行代码能够使用Visual Studio 2013编译通过。然而,该编译器仅会因为语法错误而产生警告,对于多个const仅会产生警告。因此,可能存在两个问题:(1) 当你进行测试时,你没有提高警告级别;(2)当你在这里发布代码时,添加的最后一个const并未被编译。 - Cheers and hth. - Alf
显示剩余7条评论
5个回答

10

在标准中,禁止在同一类型限定符序列中明确重复使用 const

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

通常情况下,在声明的完整声明符序列或类型说明符序列或尾随类型说明符序列中,最多只允许一种类型说明符。

...

const 可以与除它自己以外的任何类型说明符组合。

某些人可能认为以下引用允许这样做(由 @davidhigh 发现):

[dcl.type.cv]/1

有两个 CV 限定符,constvolatile。每个 CV 限定符在 cv-qualifier-seq 中至多出现一次。如果一个 CV 限定符出现在 decl-specifier-seq 中,则该声明的 init-declarator-list 不得为空。[ 注意:3.9.3 和 8.3.5 描述了 CV 限定符如何影响对象和函数类型。 —— 编者注 ] 冗余的 CV 限定符会被忽略。[ 注意:例如,这些可以通过 typedef 引入。—— 编者注 ]

然而,此规则是为了允许由于模板或 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.0clang 3.5.1都将拒绝编译您的代码并提供合理的诊断。


1
你可以更清楚地说明“this”是什么。有多个问题需要解决。 - Cheers and hth. - Alf
听起来合理,但对我来说似乎有冲突。是否有类似继承规则可以使用(宽松地说:[dcl.type.cv]从[dcl.type]继承此行为)? - davidhigh
我认为这里没有冲突。[dcl.type] 表示您不能重复使用 const。[dcl.type.cv] 表示冗余的 const 会被忽略,但是指出这些可以使用 typedef 引入。如果您重复使用 const,则违反了第一个规则,您的程序将不合法。如果您使用 typedef 重复使用它们,则您的程序是正常的,因为第二个规则允许这样做。 - TartanLlama
另一个想法是:这需要考虑到标准引用的给定优先级来解释。你也可以将其解释为“首先去除冗余”,然后“禁止多个常量”(这将使后者规则本身变得多余)。引用显然显示了它的意思 - 但从一个学究的角度来看,这种解释至少是可能的。 - davidhigh
正如你所说,这将使后面的规则变得多余,那么如果这是一个不可能的情况,为什么它会首先出现在标准中呢?我认为这一点就足以否定任何其他立场。 - TartanLlama
当然。我们可以在这里停止了。C++标准不是一个公理系统。再次感谢! - davidhigh

3

关于这个问题:

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

实际上并不会。代码示例不是真正的代码。例如:

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

(第一个例子)由于两个原因,任何符合标准的编译器都无法编译它:
- 在(int)开头使用多个const是不被允许的。
- 末尾的const是语法错误。
第一点的标准术语:C++11 §7.1.6/2,
“ const 可以与除其自身以外的任何类型说明符组合。

好的,我收到后会进行编辑/删除:在像 OP 这样的情况下,我的回答中的引用何时失去适用性? - davidhigh
@davidhigh:关于标准语,请参考TartanLama的回答(https://dev59.com/UIvda4cB1Zd3GeqPfea2#30798876)。在发布之前,您仍应该**检查现实情况**。当有人指出这一点时,您应该立即进行检查,而不是要求别人为您进行质量保证。如果这听起来有些粗鲁,我很抱歉。我有点生气。 - Cheers and hth. - Alf
没有问题,听起来不失礼貌,但也没有回答我的问题。 - davidhigh

1
因为标准规定如此。以下是[dcl.type.cv]的摘录,确切地说明了这一点(强调我的):
“有两个cv限定符,const和volatile。每个cv限定符在cv限定符序列中最多只能出现一次。如果cv限定符出现在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的规则(当然,这将使后者规则本身变得多余)。

在这种情况下,显然,引文显示了其意思。但是,严谨地说,除非标准引用中有某种形式的优先级,否则无需按此解释。


4
实际上这是错误的。标准禁止这样做。 - BЈовић
@BЈовић:是的,我们遇到了这个问题。解决这个看似矛盾的情况。 - davidhigh
@Cheersandhth.-Alf:你可以再看一下。 - davidhigh

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限定符在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++中,这个声明将无法编译。


关于“因为”的问题,需要注意到还存在一个语法错误,即最后的 const - Cheers and hth. - Alf
@干杯和祝好运。- 阿尔夫 谢谢 :) - Vlad from Moscow

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

    这是“OK”的,除了重复的限定符部分。


关于这里的假设,另一个假设是OP使用了#define const(什么也没有)进行测试。例如。;-) 对于其他读者:是的,可以将main用作成员函数名称。 - Cheers and hth. - Alf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接