вывести коллекцию коллекций, используя шаблонный оператор << - PullRequest
2 голосов
/ 18 апреля 2019

Я хочу вывести коллекцию коллекции (в данном случае вектор векторов), вызвав внешнюю коллекцию один раз оператором << </p>

Это работает, когда я удаляю ' ' из функции operator<<(), но я хочу, чтобы между каждым выходным элементом каждой строки был пробел. Я попытался заменить ' ' на " " (включая файл заголовка строки), но получил ту же ошибку.

Есть ли способ решить эту проблему?

#include <iostream>
#include <vector>

using namespace std;

vector<vector<bool>> lookup(10, vector<bool>(10, true));

template <typename T>
ostream& operator<< (ostream& out, const T& collection)
{
    for (const auto& elem : collection)
        out << elem << ' ';
    return out << endl;
}

int main()
{
    cout << lookup << endl;
}

Я получаю следующую ошибку:

1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>test.cpp
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(16): error C2593: 'operator <<' is ambiguous
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(13): note: could be 'std::ostream &operator <<<char>(std::ostream &,const T &)'
1>        with
1>        [
1>            T=char
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(921): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,_Elem)'
1>        with
1>        [
1>            _Elem=char
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(834): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(749): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(16): note: while trying to match the argument list '(std::ostream, char)'
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(22): note: see reference to function template instantiation 'std::ostream &operator <<<std::vector<std::vector<bool,std::allocator<_Ty>>,std::allocator<std::vector<_Ty,std::allocator<_Ty>>>>>(std::ostream &,const T &)' being compiled
1>        with
1>        [
1>            _Ty=bool,
1>            T=std::vector<std::vector<bool,std::allocator<bool>>,std::allocator<std::vector<bool,std::allocator<bool>>>>
1>        ]
1>Done building project "test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

1 Ответ

5 голосов
/ 18 апреля 2019

Проблема в том, что T из вашего шаблона не ограничивается конкретным типом или диапазоном типов. Компилятор может заменить его любым типом, который он хочет.

Когда вы пишете out << ' ';, компилятор ищет функцию ostream& operator<< (ostream& out, const char& collection) и находит две такие функции. Один из них из стандартной библиотеки, а другой - ваша функция. Компилятор не может решить, какую версию он должен использовать, поэтому он просто останавливает компиляцию.

Чтобы решить эту проблему, вам нужно ограничить свой шаблон, чтобы он не принимал типы, которые вам не нужны. Один из способов сделать это - создать шаблон, который принимает только vector:

#include <iostream>
#include <vector>

using namespace std;

vector<vector<bool>> lookup(10, vector<bool>(10, true));

template <typename T>
ostream& operator<< (ostream& out, const vector<T>& collection)
{
    for (const auto& elem : collection)
        out << elem << ' ';
    return out << endl;
}

int main()
{
    cout << lookup << endl;
}

Если вам нужно определить эту функцию для большего количества типов контейнеров, вместо того, чтобы копировать ее несколько раз, вы можете создать шаблон, который принимает все типы, но у него нет имени, которое конфликтует со стандартной библиотекой. Затем вы можете создать несколько простых экземпляров operator<<, которые будут вызывать только вашу универсальную функцию.

#include <iostream>
#include <vector>
#include <array>

using namespace std;

vector<vector<bool>> lookup(10, vector<bool>(10, true));

template <typename T>
ostream& printCollection (ostream& out, const T& collection)
{
    for (const auto& elem : collection)
        out << elem << ' ';
    return out << endl;
}

template <typename T>
ostream& operator<< (ostream& out, const vector<T>& collection)
{
    return printCollection(out, collection);
}

template <typename T, size_t N>
ostream& operator<< (ostream& out, const array<T, N>& collection)
{
    return printCollection(out, collection);
}

int main()
{
    cout << lookup << endl;
}

Я думаю, что это было бы даже возможно без определения функции для каждого типа контейнера отдельно. Это потребует некоторой магии шаблонов высокого уровня. Вы можете прочитать этот шаблонный класс c ++; функция с произвольным типом контейнера, как его определить? , чтобы узнать больше об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...