注册 登录
编程论坛 C++教室

用remove去除iterator中的const属性问题

花脸 发布于 2018-12-24 22:30, 3687 次点击
#include <iostream>
#include <type_traits>
using namespace std;

int main()
{
    string s="123456";
    string::iterator it=remove_const<s.begin()>::type ;
    return 0;
}
s.begin()返回一个临时变量,是一个右值,它不能赋值给一个非const的引用:所以我想要把他的const属性去掉。


[此贴子已经被作者于2018-12-24 22:34编辑过]

13 回复
#2
rjsp2018-12-25 08:21
看不懂你想干什么?
程序代码:
#include <iostream>
using namespace std;

int main()
{
    string s = "123456";
    string::iterator itor = s.begin();
}

#3
花脸2018-12-25 12:46
回复 2楼 rjsp
因为s.begin()返回的值不是带有const属性吗。想把s.begin()只用的const属性去掉。
#4
rjsp2018-12-25 13:00
以下是引用花脸在2018-12-25 12:46:07的发言:

因为s.begin()返回的值不是带有const属性吗。
不是
begin() 返回 string::iterator
begin() const 返回 string::const_iterator
#5
花脸2018-12-25 19:35
#include <iostream>
#include <type_traits>
using namespace std;

void f(string::iterator &it)
{
    ++it;
}
int main()
{
    string s="123456";
    f(s.begin());//这行出错,
    return 0;
}
[Error] invalid initialization of non-const reference of type 'std::basic_string<char>::iterator& {aka __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&}' from an rvalue of type 'std::basic_string<char>::iterator {aka __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >}'

[Note] in passing argument 1 of 'void f(std::basic_string<char>::iterator&)'
我百度的原因说是因为s.begin()返回的iterator带const,把const属性去掉即可。https://blog.

在STL中,我们能见到很多函数的形参都是iterator的传值,而不是传引用。
这是因为我们通常这么用:
void print_vector(vector<int>::iterator beg, vector<int>::itertor end);
while(beg != end) { cout << *beg++ << endl; }
print_vector(v.begin(), v.end());
这里形参如果是引用的话,则编译时会报错,因为v.begin()返回的是一个临时变量,是一个右值,它不能赋值给一个非const的引用:
error: invalid initialization of non-const reference of type 'std::vector<int>::iterator& {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >&}' from an rvalue of type 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}'
但可以赋值给const 引用;即如果print_vector的形参是const的iterator,就可以传v.begin()给它。但这样一来,在函数体内就不能做++,--或任何修改该iterator的操作了。
这就是iterator一般用传值的原因。
类似的道理,函数的返回值通常不能传给一个非const的引用,因为函数返回值通常也是一个临时变量,是一个右值。
int f() { return 1; }
int &ri1 = f();            //error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
const int &ri2 = f();   // OK
#6
rjsp2018-12-25 20:13
不可以 non-const 引用一个临时对象
而非 begin() 返回了const类型
#7
Jonny02012018-12-25 20:27
5 楼那个例子, 没有那么干的
一个函数需要迭代器都是需要迭代器底层的内容, 而不是单单需要迭代器
你没有理解 STL 使用的迭代器模式是为了什么
程序代码:
void func(std::string::iterator begin, std::string::iterator end) {
    while(begin != end) {
        //...
    }
}

这才是迭代器该做的事情
需要迭代器的函数都是对迭代器底层的内容干些什么, 而不是对迭代器干些什么
另外, string::begin() 返回的是一个纯右值
可以接受它的只有 string::iterator && 或者 string::iterator 或者 const string::iterator &

[此贴子已经被作者于2018-12-25 20:28编辑过]

#8
花脸2018-12-25 20:27
回复 6楼 rjsp
是不是没法在函数的参数列表里调用iterator的引用了?例如:
void f(string::iterator &it)
{
    ++it;
}
#9
Jonny02012018-12-25 20:34
对于 string::iterator 和 string::const_iterator
对他们的 const 限定是假的
他们没有 const 限定
string::iterator 的原型在 libcpp 里面是 __wrap_iterator<char *>
string::const_iterator 的原型是 __wrap_iterator<const char *>
想要从 string::const_iterator 转为 string::iterator 需要 reinterpret_cast 帮忙
程序代码:
#include <iostream>

using namespace std;
int main(int argc, char *argv[]) {
    string str {"12345"};
    auto const_iterator {str.cbegin()};
    auto non_const_iterator {*reinterpret_cast<string::iterator *>(&const_iterator)};
    while(non_const_iterator != str.cend()) {
        ++*non_const_iterator;
        ++non_const_iterator;
    }
    cout << str << endl;     //23456
}
#10
Jonny02012018-12-25 20:37
回复 8楼 花脸
这个就相当于 C 的指针, 有一个左值就行了
程序代码:
#include <iostream>

using namespace std;
void func(string::iterator &it) {
    ++it;
}
int main(int argc, char *argv[]) {
    string str {"12345"};
    auto iterator {str.begin()};
    func(iterator);
}
#11
花脸2018-12-25 21:10
以下是引用Jonny0201在2018-12-25 20:34:17的发言:

对于 string::iterator 和 string::const_iterator
对他们的 const 限定是假的
他们没有 const 限定
string::iterator 的原型在 libcpp 里面是 __wrap_iterator<char *>
string::const_iterator 的原型是 __wrap_iterator<const char *>


string::const_iterator 的原型是 __wrap_iterator<const char *>中的const char *不是用const限定了指针指向元素不能改变吗?
#12
花脸2018-12-25 21:12
以下是引用Jonny0201在2018-12-25 20:37:49的发言:

这个就相当于 C 的指针, 有一个左值就行了


    string str {"12345"};
    auto iterator {str.begin()};
    func(iterator);

这里为什么把str.begin()付给一个左值,然后函数中调用左值就可以了呢?

这种初始化的方式string str {"12345"};和这种string str ("12345");string str="12345";有什么区别没?
#13
rjsp2018-12-26 09:06
假如 non-const左值引用一个临时对象 是合法的,也就是假设下面的代码是合法的
程序代码:
int foo()
{
    return 1;
}

int main( void )
{
    int& a = foo();
    a = 2;
}
那么它岂不是相当于
程序代码:
int foo()
{
    return 1;
}

int main( void )
{
    foo() = 2;
}

#14
花脸2018-12-26 10:07
回复 13楼 rjsp
好的 明白了 谢谢。
1