我正在寻找有关如何做某事的示例,看到了这两种变体:
std::string const &s;
const std::string &s;
在不同的片段中。
谢谢你的回答 :)
std::string const &
等同于 const std::string &
。
const std::string &
是斯特劳斯特鲁普(Stroustrup)在《C++程序设计语言》中采用的风格,可能是“传统风格”。
std::string const &
可能比另一种风格更加一致:
const-on-the-right 风格总是将 常量(const) 放在它所修饰的对象的右侧,而其他风格有时会将 常量(const) 放在左侧,有时则放在右侧。
使用 const-on-the-right 风格,定义一个本地变量为常量,常量位于右侧:
int const a = 42;
。同样地,定义一个静态变量为常量,常量位于右侧:static double const x = 3.14;
。基本上,每个常量都出现在其所修饰的对象的右侧,包括必须位于右侧的常量:具有常量成员函数的对象。
(请参见“X const& x” 和 “X const* p” 是什么意思?了解更多详细信息)。
如果你决定使用 const-on-the-right 风格,请确保不要将 std::string const &s
打成毫无意义的 std::string & const s
:
上述声明的含义是: "s
是一个指向std::string
的常量引用"。
这是多余的,因为引用总是 const
的(你永远不能重置引用以使其引用其他对象)。
const
放在右侧的原因之一是它与模板的配合。大多数人通过简单的替换来处理函数模板。例如:template <class T> void foo(const T& arg);
int* p;
foo(p);
arg
的类型是什么?你想表达的是const int*&
,也就是指向const int
指针的引用,但那是错误的。文本替换让你失望了。如果你将其写成下面这样会更好:template <class T> void foo(T const& arg);
int* const&
。也就是说,这是一个指向const
整型指针的引用。从技术上讲,它们是相同的,没有任何区别。但在某些调试器(例如lldb),即使你写成const std::string&
,你也会看到std::string const&
。
T const
而不是const T
,即使当T
是简单类型时,这些类型表达式是等效的。编写T const
还避免了多级指针声明中的不一致性,例如char const* const p;
,其中最后一个const
不能移动。这说明等价性仅适用于声明开头的基本类型。const T
,并且始终如一地使用该符号。因为在C++11之后,这是可能的,而无需使用宏。为了支持一致性,我使用了命名的类型构建器,例如template< class Some_type >
using Ptr_ = Some_type*;
因此,不是从右向左阅读
char const* const p = something;
我可以并且确实写出普通的阅读方向
const Ptr_<const char> p = something;
这种写法可能比较啰嗦,但是我现在有一些使用经验后认为它值得(当时我并不确定,只是试试看)。
主要的缺点是,虽然这种符号支持类型推断(对于函数模板的函数参数)就像直接使用C语法那样,但它不支持auto
声明的类型推断。幸运的是,由于初始化程序可以很容易地变成const
,因此唯一有问题的情况就是数组引用。迄今为止,我的实用解决方案是在这些情况下直接使用C(或更确切地说,C ++)语法,但我认为这代表了该语言的一个缺陷或漏洞,可能有一些通用解决方案,也会使其他情况变得更加容易。
Ptr_
),请参见Github上的cppx/core_language_support/type_builders.hpp文件。它们包括用于函数参数的In_
等内容。尽管有些冗长,但是我发现这也非常值得,因为它可以使意图非常清晰。然而,cppx的东西是实验性的并且可能会更改。此处链接的特定文件甚至可能被移动,但大致在那里。 :)为了证明其他人的说法(我知道rtti不会在.name()
输出中考虑constness或voltilness),这只是一个测试程序:
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::cin;
using std::endl;
int main()
{
std::string t = "BLABLA" ;
std::string t1 = "BLABLA" ;
std::string const &s = t;
const std::string &d = t1;
if (typeid(d) == typeid(s))
cout << "d and s are the same type according to the rtti" << endl;
else
cout << "d and s are the NOT the same type according to the rtti" << endl;
// here the raw output is exactly the same for both
cout << typeid(d).raw_name() << endl << typeid(s).raw_name() << endl;
cin >> t;
return 0;
}
对于gcc (4.9.2)(经过适当修改)和msdn (vs2010)来说,两者都返回"same type"。
我提供这个"答案"作为贡献而不是"答案"。
编辑:Scott-Meyers的《Effective Modern C++》第4项中分享了一些有关我所写示例的真正有趣的隐藏信息。 简而言之,由于我们通过值传递变量名,因此typeid无法产生可靠的结果。 当我们通过值传递方法中的变量时,推导出的类型失去其constness、volatilness和referenceness(缩写为cvr)。这就是为什么上面的示例不能证明这两种类型之间的区别。
同一项声明Boost项目托管了一个名为TypeIndex的库,它可以保留cvr属性。
s
是指对一个常量字符串的引用。而第二个s
是指对一个不可变的字符串的引用。也就是说,它们实际上是相同的意思。 - Some programmer dudec++filt
。 - Brett Hale