Не могу научить компилятор выводить и множества, и векторы
У меня есть две функции, для вывода вектора и множества:
template <typename Element>
ostream& operator<<(ostream& out, const set<Element>& container) {
bool isnt_first = false;
for (const Element& element : container) {
if (isnt_first) {
out << ", "s << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
}
template <typename Element>
ostream& operator<<(ostream& out, const vector<Element>& container) {
bool isnt_first = false;
for (const Element& element : container) {
if (isnt_first) {
out << ", "s << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
}
Функция main:
int main() {
setlocale(LC_ALL, "ru");
const set<string> cats = { "Мурка"s, "Белка"s, "Георгий"s, "Рюрик"s };
cout << cats << endl;
return 0;
}
Мне нужно вынести функционал вывода в отдельную функцию Print, что я и сделал:
template <typename Container, typename Element>
std::ostream& Print(std::ostream& out, const Container container) {
bool isnt_first = false;
for (const Element& element : container) {
if (isnt_first) {
out << ", "s << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
};
template <typename Element>
ostream& operator<<(ostream& out, const set<Element>& container) {
out << Print(out, &container);
return out;
}
template <typename Element>
ostream& operator<<(ostream& out, const vector<Element>& container) {
out << Print(out, &container);
return out;
}
Но компилятор выдает ошибки при компиляции:
error C2672: "Print": не найдена соответствующая перегруженная функция
std::ostream &Print(std::ostream &,const Container): не удается составить аргумент шаблон для "Element"
Как заставить программу работать и с множествами, и с векторами?
Ответы (2 шт):
Вызов Print не упоминает явно тип Element. Компилятор не понимает как его вывести из переданных аргументов. Ему можно подсказать, указав типы явно:
template <typename Container, typename Element>
std::ostream& Print(ostream& out, const Container& container) {
bool isnt_first = false;
for (const Element& element : container) {
if (isnt_first) {
out << ", " << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
}
template <typename Element>
ostream& operator<<(ostream& out, const set<Element>& container) {
return Print<const set<Element>&, Element>(out, container);
}
template <typename Element>
ostream& operator<<(ostream& out, const vector<Element>& container) {
return Print<const vector<Element>&, Element>(out, container);
}
Я добавил пропущенный & в декларации Print. И наоборот, убрал его из вызовов. Значение возвращаемое из Print отправлять на печать не надо. Уже всё напечатано.
Можно схитрить и убрать тип Element из декларации Print:
template <typename Container>
std::ostream& Print(ostream& out, const Container& container) {
bool isnt_first = false;
// for (const typename Container::value_type& element : container) {
for (const auto& element : container) {
if (isnt_first) {
out << ", " << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
}
template <typename Element>
ostream& operator<<(ostream& out, const set<Element>& container) {
return Print(out, container);
}
template <typename Element>
ostream& operator<<(ostream& out, const vector<Element>& container) {
return Print(out, container);
}
Я бы предложил вот такой вариант, в котором не нужно ограничиваться только конкретными типами контейнеров, а уж тип элемента — это дело контейнера.
template <typename Container,
typename = enable_if_t<!is_same_v<Container,string>>>
ostream& operator<<(ostream& out, const Container& container)
{
bool isnt_first = false;
for (const auto& element : container)
{
if (isnt_first) {
out << ", "s << element;
}
else {
out << element;
isnt_first = true;
}
}
return out;
}
Главное — объяснить оператору, что string — это таки не контейнер, несмотря на то, что это все же контейнер :)