带有参考参数的C ++函数为迭代器错误。寻求解释

时间:2019-03-16 08:10:07

标签: c++ reference iterator

我做了一些C ++评估问题,偶然发现了这个棘手的程序。

#include <deque>
#include <iostream>

using namespace std;

template<typename T>
ostream & print(T &start, T &end)
{
    for(; start != end; ++start)
    {
        cout<< *start<< " ";
    }
    return cout;
}

int main()
{
    int tab[]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    deque<int> d1(tab, tab+10);
    deque<int> d2;
    deque<int>::iterator it;
    for(it = d1.begin(); it != d1.end(); ++it)
    {
        d2.push_back(d1[d1.end()-it-1]);    //LINE I
    }
    print(d2.rbegin(), d2.rend()) << endl;  //LINE II
    return 0;
}

我选择了程序将成功运行并显示以下选项:1 2 3 4 5 6 7 8 9 10

我后来编译了程序以对其进行测试,但它没有与错误消息一起编译:

$g++ -o main *.cpp main.cpp: In function ‘int main()’: main.cpp:25:17: error: cannot bind non-const lvalue reference of type ‘std::reverse_iterator<std::_Deque_iterator<int, int&, int*> >&’ to an rvalue of type ‘std::deque<int>::reverse_iterator {aka std::reverse_iterator<std::_Deque_iterator<int, int&, int*> >}’   print(d2.rbegin(), d2.rend()) << endl; //LINE II
        ~~~~~~~~~^~ main.cpp:6:32: note:   initializing argument 1 of ‘std::ostream& print(T&, T&) [with T = std::reverse_iterator<std::_Deque_iterator<int, int&, int*> >; std::ostream = std::basic_ostream<char>]’  template<typename T> ostream & print(T &start, T &end)
                                ^~~~~

此错误消息实际上是选项之一,但我认为它不会编译。

我不太了解问题所在。我发现如果我按以下方式更改print函数的参数,那么它将编译并成功运行:

template<typename T> ostream & print(T start, T end)
{
    for(; start != end; ++start)
    {
        cout<< *start<< " ";
    }
    return cout;
}

为什么?如果print函数的参数是引用,如何理解错误消息?

2 个答案:

答案 0 :(得分:1)

左值引用可以绑定到左值。如果print通过Lvalue引用接受其参数,则当您从rbegin/rend创建Lvalues时,可以编译代码:

auto it1 = d2.rbegin();
auto it2 = d2.rend();
print(it1,it2); // pass Lvalues

调用print(d2.rbegin(),d2.rend())时,rbegin/rend返回迭代器by value,因此这些迭代器是临时对象,并且由于将临时对象(Rvalue)绑定到Lvalue引用是非法的,因此您的代码不会t编译。

迭代器是轻量级对象,您无需通过引用传递它们,只需复制它们即可。

答案 1 :(得分:0)

解释,如果编译器错误

print函数的参数是引用,但是const引用仍然是引用。如果我有一个按值返回的表达式(例如d2.begin()),那么它只能绑定到const引用,因此您的print函数将被const引用调用。

修复

由于print采用迭代器,因此您应该按值传递它们。迭代器很容易复制(而且编译器通常可以直接将其传递到CPU的寄存器中,因此甚至不需要复制)。我们只需删除引用即可重写print

template<typename T>
ostream & print(T start, T end)
{
    for(; start != end; ++start)
    {
        cout<< *start<< " ";
    }
    return cout;
}