为什么有些人更喜欢“T const&”超过“const T&”?

时间:2010-04-14 19:36:16

标签: c++ syntax pointers reference types

所以,我意识到const T&T const&是相同的,都表示对const T的引用。在这两种情况下,引用也是常量(与指针不同,引用不能重新分配)。我观察到,在我有点经验的情况下,大多数C ++程序员都使用const T&,但我遇到过一些使用T const&的人。我使用const T&只是因为我是这样学习的,所以T const&看起来对我来说有点滑稽。您使用您使用的变体的原因是什么?你们中的任何一个人是否在一个组织中工作,编码标准要求使用一种变体而不是另一种变体?

修改
根据答案,似乎在两者之间进行选择的一个原因是你是否想要像编译器(从右到左)或像英语(从左到右)那样阅读它。如果像编译器一样读它,那么“T const&”读作“&(参考)const(到常数)T(T型)”。如果从英语中读取它,从左到右,那么“const T&”被读作“以引用形式存在的T类型的常量对象”。我更喜欢像英文散文一样阅读它,但我当然可以通过编译器的方式来理解它。

没有人回答组织或编码标准问题,但我强烈怀疑大多数组织并没有强制要求一个,尽管他们可能会努力保持一致性。

9 个答案:

答案 0 :(得分:43)

我认为有些人只是喜欢从右到左阅读声明。 const适用于左侧令牌,除非此处没有任何内容,并且它适用于右侧令牌。因此const T&涉及“除外” - 使用,或许可以被认为更复杂(实际上两者都应该易于理解)。

比较

const T* p;  (pointer to T that is const)
T const* p;  (pointer to const T) //<- arguable more natural to read
T* const p;  (const pointer to T)

答案 1 :(得分:26)

当你有一个以上的const / volatile修饰符时,这会有所不同。然后将它放在类型的左边仍然有效,但会破坏整个声明的一致性。例如:

T const * const *p;

表示p是指向const T的const指针的指针,你从右到左一致地读取。

const T * const *p;

意思相同,但一致性会丢失,你必须记住,最左边的const / volatile只与T绑定,而不是T *。

答案 2 :(得分:7)

如果你觉得这个讨论很有趣,你可能会发现Dan Saks的this文章很有趣。它没有直接解决你的问题,但解释了为什么他更喜欢

VP const foo[];

const VP foo[];

这是因为给定

typedef void *VP;

你很容易误以为上面的第二个例子意味着

const void *foo[];  // Wrong, actually: void *const foo[];

但第一个例子更难以曲解。

答案 3 :(得分:3)

我认为是个人偏好。两种变体之间没有区别。

答案 4 :(得分:3)

由于代码主要是基于英语的,程序员倾向于从左到右阅读,因此const T&自然地读取编译器从右到左读取内容的位置,因此T const&自然地读取(引用)到const T)

答案 5 :(得分:3)

我的推理如下:

如果你写“const T&amp;”,它似乎会更好地滚动舌头但是当你这样做时,你最终会得到模棱两可的“恒定T参考”。我已经在代码的可理解性中不止一次地看到了这个问题,这些代码允许有人甚至是半经验的人误解了什么意思或如何声明更复杂的类型。

我现在想不出任何一个例子,但我不止一次回答关于类型声明和常量的问题,其中问题是由使用“const T&amp;”的习惯引起的。而不是“T const&amp;”。我曾经也是这样写的,当我成为一名高级开发人员,负责指导和创建项目代码标准的人时,我发现当我迫使所有人使用“T const&amp;”时,入门级开发人员会更容易。 。我想一个相当琐碎,新手的错误就是为什么这个代码会编译?


const T* t = f();
t = 0; // assignment to const?? - no, it is not the T* that is const, just the T.

当你学会以编译器的方式阅读它时,它变得更容易理解任何给定的复杂类型,以及允许你在需要时更容易地声明复杂类型。根据复杂的类型,我说的是:

T const * const&amp;

当你知道编译器从右到左,从里到外读取时,这意味着什么变得非常明显,当需要编写一个时,你可以轻松地做到:引用常量指针指向常量T.现在写下声明“对指向T的常量指针的指针的引用”。如果你只是使用从左到右的表示法,我想你会发现这很容易。

简而言之,虽然最初似乎不自然地教自己使用右 - >左语法,而不是只在需要时(因为它经常),你会发现更容易记住什么是代码行意味着如何写出你的意思。这与我在声明中禁止“,”的原因相同:


T* ptr1 = 0, ptr2 = 0; // oops!!!

// do it this way please! T* ptr1 = 0; T* ptr2 = 0;

从技术上讲,它完全相同,但当你试图让一群不同容量的人在同一件事上工作时,你会倾向于确保每个人都使用最容易理解和使用的方法。我的经历告诉我“T const&amp;”是那种方法。

答案 6 :(得分:1)

这是因为有些人认为从右到左阅读声明很有帮助。

char const*
const char*

都是const char的指针。

答案 7 :(得分:1)

我曾经是const T&的坚定拥护者,因为它从逻辑上从左到右读取(这是恒定T 参考)。 (并且可能会有一些偏差,因为到目前为止我遇到的大多数代码都是以这种方式编写的。)

这些年来,我遇到了一些极端的情况(例如,多个指针/引用层,多个变量声明和方法指针),由于其他人已经回答的原因,它们使事情有些紧张。通常,引入其他typedef可以在某种程度上帮助您“解开”这些情况,但是即使您只使用过一次,您也必须想出一个名称。

对我而言,引爆点是C ++ 11中auto的引入,尤其是与基于范围的for结合使用时。有了这一点,我已经翻了翻,现在强烈推荐使用T const&(或“对常量T的引用”,从右向左阅读)。它不仅与编译器的实际解析方式更加一致,还意味着当您用auto替换类型时,它总是以左侧结尾,我认为这样会更好。

比较:

for (const T& a : list)         for (T& a : list)
for (T const& a : list)         for (T& a : list)
for (const auto& a : list)      for (auto& a : list)
for (auto const& a : list)      for (auto& a : list)

还请注意右侧的列,在该列中我添加了相同的非常量版本。至少对我来说,在const出现在T之后的情况下,const与非const和auto与显式的一致性似乎最为一致。

但这是一种样式选择,因此,没有绝对正确的答案。

答案 8 :(得分:0)

如果const&相距遥远,如

krog::FlamBlott<std::map<HurkleKey,Spleen<int>>
speckleFlams( const krog::Floonage & floon, const std::map<krog::HackleSpoon,std::vector<krog::HeckleObservation<OBSN>>> & obsmap);

krog::FlamFinagleReport
finagleFlams( const krog::Floonage & floon, std::map<krog::HackleSpoon,std::vector<krog::HeckleObservation<OBSN>>> & obsmap)

...然后,很容易会错过第一个“ obsmap”是const引用而第二个不是const引用的情况。