这是我的一些上下文的示例代码:
//tac.cc
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
auto lines = vector<string>{};
for(auto line = string{}; getline(cin,line); ){
lines.emplace_back(line);
};
//vector<string>::const_reverse_iterator cit = lines.rbegin();
//auto cit = lines.rbegin();
for(
decltype(lines)::const_reverse_iterator cit = lines.rbegin();
cit != lines.rend();
++cit){
cout<< *cit << endl;
};
return 0;
}
在第二个for循环中,id auto
从const_reverse_iterator
中获得rbegin()
的简洁性。
根据http://www.cplusplus.com/reference/vector/vector/rbegin/,
vector
的{{1}}有两个签名:
rbegin
如果我确实使用
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
我得到 auto cit = lines.rbegin();
的非const版本,因为编译器然后让我修改向量(例如rbegin
)而不发出警告。
*cit = "foo";
如何从两个版本的auto
中选择。可以选择第二个版本吗?
答案 0 :(得分:3)
正如0x499602d2指出的那样,C ++ 14中有cr?[begin|end]*
个系列。事实上,您的代码基本上出现在Scott Meyer's Effective Modern C++(第13项)中,并将其作为解决方案。
目前,您可以在调用时强制lines
成为const
,如下所示:
auto cit = ((const decltype(lines) &)lines).rbegin();
虽然有其他方式,但不涉及decltype
,我喜欢这个,因为它对lines
类型的后期更改不变。
答案 1 :(得分:2)
如何从
rbegin
的两个版本中自动选择。可以选择第二个版本吗?
这是错误的问题。 auto
只选择lines.rbegin()
的类型。问题是“编译器如何选择rbegin()
?” 的答案是我们使用对象实例作为第一个参数对两个函数进行重载解析。所以我们有:
reverse_iterator rbegin(vector<string>& );
const_reverse_iterator rbegin(const vector<string>& );
两个重载都是完全匹配,但后者是对更多cv限定类型的引用(因为lines
不是const
),所以第一个是首选。这就是为reverse_iterator
获得lines.rbegin()
的原因。 auto
只是愉快地推断出它。
您想要的是强制通话本身为您提供const_reverse_iterator
,这需要您将const
对象“传递”到rbegin
。你可以明确地做到这一点:
auto cit = const_cast<const vector<string>&>(lines).rbegin();
甚至还有一个proposal可以让这更容易:
auto cit = std::as_const(lines).rbegin();
但更简单的是,只有一个成员函数始终返回const_reverse_iterator
:crbegin
auto cit = lines.crbegin();