C++:const引用,类型说明符之前和之后的区别

194

在下面两个函数参数之间有什么区别:

int foo1(const Fred &arg) {
...
}

并且

int foo2(Fred const &arg) {
...
}
我在parashift的常见问题解答中没有看到这种情况被覆盖。

6
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.8 - Oliver Charlesworth
2
这是关于风格的问题吗?“const Fred”在英语中听起来不错,但我觉得“Fred const”更好看。 - LatinSuD
1
另外,有没有任何理由更喜欢 Fred const &arg 而不是 Fred const& arg?我更喜欢后者,因为 const& 是一个单元,意思是 "constref",而名称 arg 与所有类型说明符都用空格分开。 - Frank
5
@dehmann说:但是int const& ref并不意味着“const引用”,而是“引用常量”。 - Cedric H.
1
为什么有些人更喜欢使用“T const”而不是“const T”? - Michael Aaron Safyan
@OliverCharlesworth 的链接已经失效,我认为它已经移动到这里:https://isocpp.org/wiki/faq/const-correctness#const-ref-alt - Gunther Struyf
7个回答

164

行为

const T&T const&之间没有语义上的区别;语言将它们视为相同类型。(const T*T const*也是如此。)

风格问题

然而,就风格而言,我会反对其他答案并更喜欢使用const T&(和const T*):

  • const T&是Stroustrup的《The C++ Programming Language》一书中使用的风格。
  • const T&是C++标准本身使用的风格。
  • const T*是K&R的《The C Programming Language》一书中使用的风格。
  • const T*是C标准使用的风格。
  • 由于以上因素,我认为const T& / const T*T const& / T const*具有更大的惯性。在我看过的所有C++和C代码中,const T& / const T*似乎比T const& / T const*常见得多。我认为遵循常规做法比教条地坚持从右到左的解析规则更易读。
  • 对于T const*,似乎更容易将*放错位置,写成T* const(特别是如果人们不太习惯)。相比之下,const* T不是合法的语法。

从右到左的解析规则怎么样?

关于人们喜欢使用的整个从右到左解析论点:正如我在另一个答案的评论中提到的那样,const T&从右到左阅读也很好。它是对T常量的引用。 "T"和"constant"都可以作为形容词或名词。 (此外,从右到左阅读T const*可能会产生歧义,因为它可能被错误地解释为“指向T的指针常量”而不是“指向常量T的指针”。)


5
+1,同意。当阅读代码时,如果一行以const开头,那么更容易发现这是一个常量。从左到右的规则只有在手动解析复杂类型声明时才需要。为什么不针对最常见的情况进行优化呢?此外,在我看来,如果你编写类型声明时需要在脑海中手动运行一个有限状态机,那么你做错了。 - Andreas Magnusson
2
无论你的结论有多么合理,我个人多么同意它们,它们都没有直接回答所问的问题。这使得对一个简单问题的第二个最佳答案看起来像是关于一些混乱的水下机械的离题胡言,没有结论,没有直接回答——什么也没有。当你添加一个简单明确的摘要声明“不,两种语法之间没有语义差异,但有一些风格上的考虑如下...”时,你会得到我的赞同。然后再列出所有那些项目符号。 - ulidtko
1
在我看来,const T& 读起来更好的原因是: 1- 我们从左到右阅读代码。并且 2- 当描述一个新概念时,我们从更一般的概念开始到更具体的概念。 在这里,const 关键字更为通用,因为它将变量空间分成两个类别,而类型说明符将其分成多个类别。 - pooya13
“pointer to” 应该连在一起,这样 T const* 就不会有歧义。 - Dexter
@Dexter 虽然“指向”应该保持在一起,但这是另一件需要记住并有可能出错的事情。 - jamesdlin
显示剩余3条评论

143

没有区别,因为对于&而言,const从右往左阅读,所以两者都代表一个不可变的Fred实例的引用。

Fred& const将意味着引用本身是不可变的,这是多余的;当处理const指针时,Fred const*Fred* const都是有效但不同的。

这是一种风格问题,但我更喜欢使用const作为后缀,因为它可以一致地应用于包括const成员函数在内的所有情况。


那么让 std::is_const<const T&>::valuefalse 有什么意义呢? - abyss.7
@abyss.7 这是一个对 const T 的引用;该引用是可变的。 - Sean Fausett
1
如果按照定义,引用被绑定后是不可重新绑定的,那么如何使其可变?这正是该问题及其答案所讨论的内容——T& const 的概念是否多余?这确实是一个非常有价值的 is_const 问题,我也想知道答案。 - Violet Giraffe
@VioletGiraffe 确实,引用无法重新绑定,因此在这种意义上说,引用是不可变的。更好的做法是简单地说引用忽略对引用本身的const限定符:“引用类型不能在顶层处进行cv限定;在声明中没有语法规定,如果在typedef名称、decltype说明符或类型模板参数中添加了限定符,则会被忽略。”(参见cppreference.com - Sean Fausett

14

虽然它们是相同的,但为了保持与解析C和C++声明的右-左规则一致,更好的写法是 Fred const &arg

还可以参考这里来进一步了解声明、限定符和声明符。


1
我更喜欢使用后缀形式,因为它与typedef扩展的配合效果更好。例如:typedef int* pointer;const pointer 不是 const int*,而是int* const。后缀形式并不笨拙。 - Matthieu M.
4
IMO,const T& 从右向左理解也很清晰;它是一个指向 T 常量的引用。Tconstant 都可以作为形容词或名词使用。 - jamesdlin

8

两种方式都可以,这里是它的创作者解释
他说:

为什么?当我发明“const”(最初被命名为“readonly”,并有相应的“writeonly”)时,我允许它在类型之前或之后出现,因为我可以这样做而不会产生歧义。



4
引用与指针的工作方式不同:对于指针,您可以有“const指针”(type * const p)和“指向const”的指针(const type * ptype const * p)。

但是对于引用,您没有这个选项:引用始终将引用同一对象;从这个意义上说,您可以将“引用”视为“const引用”(就像您可以有“const指针”一样)。

因此,“type & const ref”之类的内容是不合法的。您只能拥有“type的引用”(type &ref)和“常量类型的引用”(const type &reftype const &ref;两者完全等价)。

最后,即使在英语中,“const type”听起来更正确,编写“type const”可以让人更系统地理解声明的“从右到左”: int const & ref 可以被理解为“ref是一个指向常量int的引用”。或者更复杂的例子:int const * const & ref,ref是一个指向常量指针的常量int的引用。

结论:在您的问题中,两者是完全相等的。



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