Call of overloaded is ambiguous при реализации своего алгоритма copy

201
21 октября 2021, 23:10

Есть самописное подобие stl. Суть задачи - вектор пар (тоже самописные).

Проблема появилась при попытке создать вектор с парами при включении в пару std::string. Заругалось на неоднозначность:

ошибка: call of overloaded 'copy(vector<pair<std::__cxx11::basic_string<char>, int> >::iterator, vector<pair<std::__cxx11::basic_string<char>, int> >::iterator, pair<std::__cxx11::basic_string<char>, int>*&)' is ambiguous
         copy(begin(), end(), newMemory);
         ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~

Заменяю copy(begin(), ... на std::copy(begin(), ..., и все компилируется.

Реализация алгоритма copy скопирована справочника. Там заявлено:

The behavior of this function template is equivalent to

то есть

поведение шаблона функции эквивалентно коду, приведенному ниже

В итоге, не могу понять, что не так с алгоритмом copy, взятым из справочника. Почему он не переваривает std::string если заявлено, что его поведение эквивалентно std::copy?

#include <string>
#include <algorithm>
template<class T1, class T2>
class pair
{
public:
    pair() :
        first(T1()),
        second(T2())
    {
    }
    pair(T1 _first, T2 _second) :
        first(_first),
        second(_second)
    {
    }

    T1 first;
    T2 second;
};
template<class MyInputIterator, class MyOutputIterator>
MyOutputIterator copy(MyInputIterator first, MyInputIterator last, MyOutputIterator result)
{
    while (first != last) {
        *result = *first;
        ++result; ++first;
    }
    return result;
}
template<class T>
class vector
{
public:
    vector() : _data(nullptr), _size(0) {}
    void push_back(const T &val)
    {
        reserve(_size + 1);
        _data[_size] = val;
        _size += 1;
    }
    void reserve(size_t n)
    {
        if (n > _size)
        {
            T *_newData = new T[_size + 1];
            if (_data) 
            {
                copy(begin(), end(), _newData);  //<<< ругается здесь
                delete [] _data;
            }
            _data = _newData;
        }
    }
    T* begin() { return _data; }
    T* end() { return _data + _size; }
private:
    T *_data;
    size_t _size;
};
int main()
{
    vector<pair<std::string, int>> v;
    v.push_back(pair<std::string, int>("qwerty", 5));
    return 0;
}

P.S. Это что-то вроде тренировки на кошках (во избежание комментариев типа "зачем всё это надо, если есть stl").

Answer 1

Если тип аргумента функции является специализацией шаблонного класса, то в список ассоциированных пространств имен для выполнения ADL будут включены также пространства имен, ассоциированные с типами шаблонных аргументов (см. http://eel.is/c++draft/basic.lookup.argdep#2.2). В вашем случае один из шаблонных аргументов принадлежит пространству std. Из-за этого ADL будет рассматривать std как ассоциированное пространство имен и выполнять там поиск.

В результате ваше copy конкурирует с std::copy.

Либо переименуйте свою функцию, либо используйте квалифицированное имя для вызова функции: ::copy (либо, если уж взялись, пишите свой string :) ).

Answer 2

Замените название функции на какое-нибудь другое.

Из-за argument dependent lookup, при вызове copy(...) компилятор в вашем случае находит не только вашу copy, но и std::copy, и не может выбрать между ними.

READ ALSO
C++ Считалка. Проблема с зацикливанием

C++ Считалка. Проблема с зацикливанием

Пишу код под задачу со считалкой в строке и одномерным массивом с людьмиЧерез поток делю строку на слова и через while выполняю считалку один...

243
Полиморфизм и указатели на функции

Полиморфизм и указатели на функции

Можно ли считать указатели на функции одним из способов реализации статического полиморфизма?

69
Очередь на языке С++

Очередь на языке С++

Пытаюсь решить следующую задачу: создать пользовательскую очередь, в которой каждый элемент равен сумме предыдущих, первый элемент равен...

62
Что я упустил text text

Что я упустил text text

Получается бесконечный цикл

87