неявное const приведение в шаблонах - PullRequest
0 голосов
/ 10 ноября 2011

Я столкнулся с чем-то похожим на приведенный ниже фрагмент кода, который выдает ошибку компилятора, поскольку он использует const_iterator.есть ли причина, по которой vec.end() в std::copy неявным образом не получает const приведение?

int main(int argc, char* argv[]) {

    vector<int> vec;
    vec.push_back(20);
    vec.push_back(30);
    vector<int> copy_vec;
    vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(copy_vec));
    cerr<<copy_vec.size()<<endl;
    return 0;
}

Ответы [ 3 ]

5 голосов
/ 10 ноября 2011

Нет необходимости в std::copy, также вам не нужна пара итераторов.

Просто сделайте это:

vector<int> copy_vec(vec); //use the copy constructor!

И все готово!

Что касается вашего кода, почему он выдает ошибку, то это потому, что первый итератор для std::copy является const_iterator, а второй итератор - просто iterator. Оба должны быть одного типа, но это не так, и из-за этого вывод аргумента шаблона завершается неудачно для std::copy, который является шаблоном функции.

Чтобы понять это на примере, рассмотрим следующий простой код:

template<typename T>
void f(T a, T b) {}

int main()
{
    int a = 100;
    char b = 'A';
    f(a,b);
}

выдает ошибку (см. ideone ):

prog.cpp:8: error: no matching function for call to ‘f(int&, char&)’

Он не компилируется, потому что мы полагаемся на вывод аргумента шаблона . Поскольку тип первого параметра и второго параметра равен точно , то же самое в шаблоне функции, но мы вызываем эту функцию, передавая a (что составляет int) в качестве первого аргумента и b (что является char) как второй аргумент, он не может однозначно вывести T из аргументов разных типов! Обратите внимание, что преобразование не учитывается при выводе аргумента шаблона.

Однако, если мы не будем полагаться на вывод аргумента шаблона и вместо этого явно предоставим аргумент шаблона, он будет работать (см. ideone ):

f<int>(a,b);  //works!

Работает, так как нет необходимости выводить T из аргументов функции!

Аналогично, если вы предоставите аргумент шаблона для std::copy, тогда будет работать даже ваш код (см. ideone ):

std::copy<vector<int>::const_iterator>(i,vec.end(),back_inserter(copy_vec));
       //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicitly provide template argument!

Это работает, потому что iterator может конвертировать в const_iterator, но const_iterator не может конвертировать в iterator, что означает, что следующее выдаст ошибку (см. ideone ):

std::copy<vector<int>::iterator>(i,vec.end(),back_inserter(copy_vec));
        //^^^^^^^^^^^^^^^^^^^^^ non-const iterator!
1 голос
/ 10 ноября 2011

vec - неконстантный вектор, поэтому end вернет неконстантный итератор. Такой итератор на самом деле не может быть неявно преобразован в константную версию, потому что это отдельные классы.

Вместо этого используйте конструктор двух итераторов:

vector<int> copy_vec(vec.begin(), vec.end());

0 голосов
/ 10 ноября 2011

Я думаю, что проблема здесь в том, что объявлено, что std :: copy принимает три параметра.

Первые два имеют одинаковый тип, и вы передаете ( const_iterator, vec.end () ) - и vec.end () возвращает неконстантный итератор (потому что vec - неконстантный вектор). Это приводит к тому, что компилятор отклоняет шаблон для std :: copy.

Если у вас была такая функция:

void doit ( const std::vector<int> &vec, std::vector<int> &out ) {
    std::vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(out));
    }

Тогда он скомпилируется и будет работать нормально, потому что vec.end () вернет const_iterator. Кроме того, если вы используете C ++ 11, вы можете вызвать vec.cend (), чтобы получить const_iterator.

...