关于c ++:“ std :: string const&s”和“ const std :: string&s”之间有什么区别?

What is the difference between “std::string const &s” and “const std::string &s”?

我一直在寻找有关如何做某事的示例,并看到了这两种变体:

1
2
std::string const &s;
const std::string &s;

在不同的片段中。

谢谢你的回答:)


std::string const &等效于const std::string &

const std::string &是Stroustrup的C ++编程语言采用的样式,并且可能是"传统样式"。

std::string const &可能比替代方法更一致:

the const-on-the-right style always puts the const on the right of what it constifies, whereas the other style sometimes puts the const on the left and sometimes on the right.

With the const-on-the-right style, a local variable that is const is defined with the const on the right: int const a = 42;. Similarly a static variable that is const is defined as static double const x = 3.14;. Basically every const ends up on the right of the thing it constifies, including the const that is required to be on the right: with a const member function.

(有关更多详细信息,请参见" X const&x"和" X const * p"是什么意思)。

如果决定使用const on-the-right样式,请确保不要将std::string const &s键入为荒谬的std::string & const s

上面的声明意味着:" s是对std::stringconst引用"。
这是多余的,因为引用始终为const(您永远不能重置引用以使其引用其他对象)。


从技术上讲,它是相同的,没有任何区别。但是,在某些调试器(肯定是lldb)中,即使您编写为const std::string&,也会看到std::string const&


正如Barry在回答中所指出的那样,旧的C语法(以及该语法的C ++扩展名)不像数学中那样支持文本替换的概念性视图。

因此,直接使用C语法通常是写T const而不是const T的好主意,即使T是简单类型,这些类型表达式也是等效的。编写T const还可避免在多级指针声明(如char const* const p;)中出现不一致,在该声明中不能移动最后一个const。这说明等价仅适用于声明开始时的基本类型。

几个月前,我开始编写const T的实验,并始终使用该表示法。因为现在可以在C ++ 11之后实现,而无需使用宏。为了支持一致性,我使用了命名类型构建器,例如

1
2
template< class Some_type >
using Ptr_ = Some_type*;

因此,而不是从右到左读取

1
char const* const p = something;

我可以写普通的阅读方向

1
const Ptr_<const char> p = something;

它有点冗长,但是我现在有了一些使用它的经验,认为这是值得的(我不确定那是实验)。

主要缺点是,尽管此表示法支持(功能模板)函数参数的类型推导,就像直接使用C语法一样,但它不支持auto声明的类型推导。令人高兴的是,由于可以轻松地将初始化程序设置为const,因此唯一有问题的情况是引用数组。到目前为止,我的务实解决方案是在这种情况下直接使用C(或更确切地说,C ++)语法,但是我认为这代表了该语言的缺点或漏洞,可能有一些通用的解决方案也可以使事情变得更加简单。其他情况。

对于我当前的类型生成器,例如Ptr_,请参阅Github上的cppx / core_language_support / type_builders.hpp文件。它们包括In_用于函数参数。是的,尽管有些冗长,但我还是清楚地知道这是值得的,因为它使意图非常清晰。但是,cppx的内容是实验性的,随时可能更改。链接到此处的特定文件甚至可以移动,但是会在附近移动。 :)


如前所述,它们是同一类型。喜欢右侧const的原因之一是它如何与模板一起使用。大多数人只是通过替换来处理功能模板。例如:

1
2
3
4
template <class T> void foo(const T& arg);

int* p;
foo(p);

arg是什么类型?您想说const int*&,也就是说,是对const int指针的引用,但这是错误的。文字替换使您失败。如果你写了它,就像

1
template <class T> void foo(T const& arg);

然后,简单的文本替换将产生正确的类型:int* const&。即,对const的引用指向int的指针。


只是为了证明其他人的断言(我了解rtti不会在.name()输出中引入常数或波动性)

这个测试程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 #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)对于两者均返回"相同类型"。

我将此"答案"作为贡献而不是"答案"。

编辑:阅读Scott-Meyers的" Effective Modern C ++"中的第4项,分享了有关我编写的示例的一些非常有趣的隐藏信息。
简而言之,由于我们通过值传递变量名,因此typeid不会产生可靠的结果。
当我们通过值传递变量的方法时,推导的类型将失去其常量性,易变性和参考性(因为对上帝的爱将被缩短为cvr)。这就是为什么上面的示例无法证明两种类型之间是否存在差异的原因。

同一项目指出,Boost项目托管一个名为TypeIndex的库,该库保留了cvr属性。