Как перегрузить оператор << для добавления элементов в вектор с помощью функции шаблона? (C ++) - PullRequest
0 голосов
/ 08 мая 2018

Я работаю над проектом для школы, и мой учитель хочет, чтобы мы перегрузили оператор «<<», чтобы он добавлял элементы в вектор. Он также хочет, чтобы мы использовали шаблон, чтобы его можно было использовать для любого типа элемента. </p>

Вот мой код заголовочного файла:

template<typename T>
vector<T>& operator<<(vector<T>& v, const T element) {
    v.push_back(element);
    return v;
}

А вот что я пытаюсь запустить:

v1 << "Atlanta" << "Dallas" << "Chicago" << "Boston" << "Denver";

Я получаю ошибку:

error C2676: binary '<<': 'std::vector<std::string,std::allocator<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator

Может кто-нибудь помочь мне с тем, почему это не работает? Я использую последнюю версию Visual Studio и правильно добавила свои файлы в решение и все остальное. Это работало некоторое время, когда я некоторое время заменял «const T element» на «const string element», но как только я снова добавил реализацию, это не сработало. Спасибо за совет.

РЕДАКТИРОВАТЬ: Спасибо за помощь, вот ответ, который закончил работать на меня:

template<typename T, typename U>
vector<T>& operator<<(vector<T>& v, const U& element) {
    v.push_back(element);
    return v;
}

Ответы [ 4 ]

0 голосов
/ 09 мая 2018

Чтобы добавить к решение с помощью emlai , лучше использовать идеальную переадресацию аргументов:

template<typename T, typename U>
std::vector<T>& operator<<(std::vector<T>& v, U&& element) {
    v.emplace_back(std::forward<U>(element));
    return v;
}

В отличие от решения, использующего std::move @emlai, здесь используется идеальное перенаправление аргументов, которое может непосредственно перемещать объект в вектор, а не передавать его по значению.

Редактировать: изменено для использования emplace_back, как описано в комментариях

0 голосов
/ 08 мая 2018

Следующее скомпилируется, если тип векторных элементов и аргументы оператора совпадают:

std::vector<const char*> v1;
v1 << "Atlanta" << "Dallas" << "Chicago" << "Boston" << "Denver";

Аналогично использование литералов std::string также будет работать для вектора std::string s:

using namespace std::string_literals;
std::vector<std::string> v1;
v1 << "Atlanta"s << "Dallas"s << "Chicago"s << "Boston"s << "Denver"s;

Можно получить массивы char непосредственно в элементы std::string, добавив другой шаблон:

//this template will accept the const char array and construct a string
template<class T, class S,  size_t N>
std::vector<S>& operator<<(std::vector<S>& v, const T(& arr)[N]) 
{
    v.push_back({std::begin(arr), std::end(arr)});
    //v.push_back(arr); // would also work for char
    return v;
}
0 голосов
/ 08 мая 2018

Когда вы используете

v1 << "Atlanta" << "Dallas" << "Chicago" << "Boston" << "Denver";

параметр T не выводится на std::string. Выводится до ‘const char [8] для "Atlanta". Типы для других аргументов будут выведены аналогично.

Измените функцию, чтобы тип элемента выводился из std::vector.

template<typename Vector>
Vector& operator<<(Vector& v, typename Vector::value_type const& element) {
    v.push_back(element);
    return v;
}
0 голосов
/ 08 мая 2018

Строковые литералы, такие как "Atlanta", не относятся к типу std::string (это массивы char), но ваша функция требует, чтобы тип векторного элемента и тип аргумента правого оператора были одного типа.

Если вы позволите типу правого аргумента отличаться, он будет работать, например ::

template<typename T, typename U>
std::vector<T>& operator<<(std::vector<T>& v, U&& element) {
    v.emplace_back(std::forward<U>(element));
    return v;
}

Обратите внимание, что я перемещаю аргумент в вектор, чтобы избежать ненужной глубокой копии, если, например, std::string передается по значению.

Редактировать: изменено для использования emplace_back, как обсуждалось в комментариях

...