"std::string const &s"和"const std::string &s"有什么区别?



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

std::string const &s;
const std::string &s;

在不同的片段中。

感谢您的回答:)

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

const std::string &是Stroustrup的The C++ Programming Language中采用的风格,可能是"传统风格"。

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

右侧的 const 样式总是将const放在其所包含内容的右侧,而另一种样式有时将const放在左侧,有时放在右侧。

使用右侧的 const 样式,使用 const 在右侧的 const 定义局部变量:int const a = 42; 。类似地,常量静态变量定义为static double const x = 3.14;。基本上每个const最终都位于它所包含的事物的右侧,包括需要位于右侧的const:具有 const 成员函数。

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

如果您决定使用正确的常量样式,请确保不要错误地将std::string const &s键入为无意义的std::string & const s

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

从技术上讲,它是相同的,没有任何区别。但是在某些调试器(当然是lldb)中,即使您编写为const std::string&,您也会看到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指向int的指针的引用。

正如Barry在他的回答中指出的那样,旧的C语法(以及该语法的C++扩展)不支持文本替换的概念观点,就像在数学中一样。

因此,直接使用 C 语法通常最好编写 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()输出)

此测试程序:

 #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) 都返回两者的"相同类型"。

我打算把这个"答案"作为一种贡献,而不是一个"答案"。

编辑:阅读斯科特 - 迈耶斯的"有效现代C++"中的第4项,分享了一些关于我写的例子的非常有趣的隐藏信息。简而言之,typeid 不会产生可靠的结果,因为我们是按值传递变量名称的。当我们按值向方法传递变量时,推导的类型会失去其恒定性、易失性和参考性(因为上帝的爱将缩短为 cvr)。这就是为什么上面的例子不能证明这两种类型之间是否存在差异。

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

最新更新