Функция C ++ с ошибками опорных параметров для итератора. Ищу объяснения - PullRequest
0 голосов
/ 16 марта 2019

Я сделал несколько вопросов об оценке 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 ]

1 голос
/ 16 марта 2019

Ссылка на Lvalue может быть привязана к Lvalue.Если print принимает свои аргументы по ссылке Lvalue, ваш код может компилироваться при создании Lvalue из rbegin/rend:

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

Когда вы вызываете print(d2.rbegin(),d2.rend()), rbegin/rend возвращает итератор по значению , поэтому эти итераторы являются временными объектами, и поскольку привязка временного объекта (Rvalue) к ссылке Lvalue недопустима, ваш код не компилируется.

Итераторы - это легковесные объекты, вам не нужно их передаватьпросто скопируйте их.

0 голосов
/ 16 марта 2019

Объяснение, если ошибка компилятора

Параметры функции print являются ссылками, но ссылка const остается ссылкой.Если у меня есть выражение, которое возвращает значение (например, d2.begin()), то оно может связываться только с константной ссылкой, поэтому ваша функция печати вызывается с константными ссылками.

Исправление

Поскольку print принимает итераторы, вы должны просто передать их по значению.Копировать итераторы тривиально (и часто компилятор может передавать их непосредственно в регистры процессора, поэтому копирование даже не требуется).Мы можем переписать print, просто удалив ссылки:

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