как шаблон для оператора << для ostream - PullRequest
3 голосов
/ 28 октября 2010

Следующее не скомпилирует для меня.У меня нет идей ... Любая помощь?

template<>
inline
std::ostream& operator<< <const std::map<std::string, std::string> > (std::ostream& stream, const std::map<std::string, std::string>& some_map)
{
  return stream;
}

g ++ выдает мне следующую ошибку:

ошибка: ожидаемый инициализатор перед маркером '<' </strong>

Редактировать: 1 Хорошо, так как все говорят, что я перегружаюсь, приведу пример, который не имеет смысла для перегрузки.Что, если у меня есть это:

template <typename T>
inline
std::ostream& operator<<(std::ostream& stream, const T& something)
{
  stream << something.toString();
  return stream;
}

class Foo
{
public:
  Foo(std::string s)
  {
    name = s;
  }

  std::string toString() const 
  {
    return name;
  }

private:
  std::string name;
};

class Bar
{
public:
  Bar(int i)
  {
    val = i;
  }

  std::string toString() const 
  {
    std::ostringstream stream;
    stream << val;
    return stream.str();
  }

private:
  int val;
};

int main(int, char**)
{
  Foo foo("hey");
  Bar bar(2);

  std::cout << foo << std::endl;
  std::cout << bar << std::endl;
  return 0;
}

Теперь это тоже не сработает.

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

В таком сценарии перегрузка для Foo и Bar для выполнения одной и той же вещи будет пустой тратой, поэтому я стараюсь избегатьэто.

Редактировать: 2 Хорошо, похоже, меня неправильно поняли.Вот еще одна попытка уточнить:

template <typename T>
std::ostream& operator<<(ostream& stream, const T& t)
{
  for(typename T::const_iterator i = t.begin(), end = t.end(); i != end; ++i)
  {
    stream << *i;
  }
  return stream;
}

int main(int, char**) 
{
  set<int> foo;
  list<string> bar;
  vector<double> baz;

  cout << foo << " " bar << " " << baz << endl;
};

Приведенный выше код не сработает.Жалуется на неоднозначность.Но, похоже, лучшее решение для распечатки контейнеров.Если бы я делал это с перегрузкой, мне нужно было бы написать версию оператора << для каждой комбинации контейнер / тип данных, что привело бы к смешному количеству дублирования кода. </p>

Ответы [ 3 ]

5 голосов
/ 28 октября 2010

Это не обязательно должна быть функция шаблона.

std::ostream & operator<<(std::ostream & stream, const std::map<std::string, std::string> & some_map)
{
    return stream;
}

Редактировать :

В связи с моим комментарием о написании Java на C ++ (и извинитеесли это звучит грубо, я не собираюсь быть умным).Скажи мне, если это не сработает для тебя.Вместо того, чтобы писать метод toString, просто перегрузите оператор << для начала.Функция практически идентична.Затем вы можете написать не принадлежащий шаблону функцию toString, которая будет автоматически работать со всеми вашими классами, например: </p>

#include <sstream>
#include <string>

template<typename T>
std::string toString(const T & val)
{
    std::ostringstream ostr;
    ostr << val;
    return ostr.str();
}

Edit 2

Вот мойАльтернатива, если вы все еще настаиваете на том, чтобы делать это по-своему.Сделайте все ваши классы с помощью метода toString наследуемыми от абстрактного класса с виртуальным методом toString, затем напишите один оператор << для обработки всех из них. </p>

class Stringifiable
{
public:
    virtual std::string toString() const = 0;
};

std::ostream & operator<<(std::ostream & ostr, const Stringifiable& something)
{
    return ostr << something.toString();
}

Теперь компилятор выберет вашу перегрузку над шаблонами.

3 голосов
/ 28 октября 2010

Вы можете использовать SFINAE для снятия перегрузки шаблона с рассмотрения.Обратите внимание, что это должно быть частью подписи функции.Таким образом, вы можете использовать boost :: enable_if:

template < typename T >
typename boost::enable_if< meta_function_to_check_for_concept<T>, std::ostream&>::type
operator << (std::ostream & out, T const& t)
{
  ...
}

Если вы этого не сделаете, ваш шаблон будет пытаться соответствовать практически чему угодно и будет взрываться при каждом использовании <<, которое не соответствуетКонцепция, которую вы пытаетесь сопоставить. </p>

Ваш пример немного надуман и может не подойти к этому ответу, но есть ситуации, в которых он оправдан.Вот как это сделать.

0 голосов
/ 06 марта 2014

В ответе Сумасшедшего Эдди он упоминает СФИНА. Теперь в C ++ 11 это встроено. Если все типы происходят из одного базового класса, это делается довольно просто. Вот более полный пример использования C ++ 11:

#include <type_traits>
#include <iostream>
#include <ostream>

class MyBaseType {};
class MyClass : MyBaseType {};
class MyOtherClass : MyBaseType {};
class SomeType {};

template <typename T>
typename std::enable_if<std::is_base_of<MyBaseType,T>::value,std::ostream&>::type
operator<<(std::ostream& out, const T& x)
{
    out << 1;
}

int main()
{
    MyBaseType x;
    MyClass y;
    MyOtherClass z;
    SomeType i;
    std::cout << x << y << z; // success!
    std::cout << i; // compile-time failure!
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...