как шаблонизировать функцию в контейнере STL, который имеет итератор - PullRequest
1 голос
/ 11 января 2011

Я хотел бы написать функцию, которая будет принимать контейнер stl (например, set, vector или list) а затем переберите содержимое, затем добавьте их в строку и верните строку.

Примерно так.

// I dont know how to do this. Just using stl::container for meanings sake Not sure if such a thing exists?
template<typename T, typename Container = stl::container<T> >  
void JoinToString(const Container<T> cont, const char * delim, string &str)
{
   stringstream s;
   Container<T>::const_iterator it = cont.begin, last = cont.end();
   while(it != last)
   {
       s<<(*it);
       ++it;
       if(it == last)
           break;
       s<<delim;
   }
   str = s.str();
} 

Я хочу что-то на этот счет. Не уверен, как написать такой код.

Ответы [ 8 ]

7 голосов
/ 11 января 2011

Стиль STL состоит в том, чтобы передавать итераторы begin и end любому алгоритму, а не самому контейнеру: это сохраняет общие принципы и позволяет использовать собственные векторы с указателями.Общие соображения в отношении стиля C ++ также предполагают возврат std::string вместо использования ссылочного параметра.

1 голос
/ 12 января 2011

Другое решение, которое делает именно то, что вы хотите, это boost::algorithm::join:

Этот алгоритм объединяет все строки в списке в одну длинную строку. Сегменты объединяются заданным разделителем.

Пример использования:

#include <boost/algorithm/string/join.hpp>
#include <boost/assign/list_of.hpp>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> v = boost::assign::list_of("A")("B")("C");
    std::cout << boost::algorithm::join(v, "/") << std::endl;
}

Выходы: A/B/C

1 голос
/ 11 января 2011

Если вам действительно нужен доступ к контейнеру, то это сделает то, что вы хотите:

template<typename Container>  
void JoinToString(const Container& cont, const char * delim, string &str)
{
  typedef typename Container::value_type T;
  ...
}

Однако более идиоматично использовать такой диапазон итераторов, как этот:

template<typename FwdIt>  
void JoinToString(FwdIt it, FwdIt end, const char * delim, string &str)
{
  typedef typename std::iterator_traits<Container::iterator>::value_type T;
  while(it != end)
  {
     ...
  }
}
1 голос
/ 11 января 2011

Вы должны решить, что вы хотите.Вы можете передать тип или шаблон.Не оба.В опубликованном вами коде вы объявляете Container типом be, но используете его как шаблон.

template<typename T, typename Container = vector<T> > 
void test() { Container x; };

template<typename T, template <typename> class Container = vector > 
void test() { Container<T> x; } 
0 голосов
/ 12 января 2011

Создайте пользовательский итератор вывода:

struct append_to_string_with_delim
  : std::iterator<std::output_iterator_tag, void, void, void, void>
{
  append_to_string_with_delim(std::string &ss, char const *dd) : s(ss), d(dd)
  {
  }
  template<typename T>
  append_to_string_with_delim &operator=(T const &t)
  {
    std::ostringstream o;
    o << t;
    s += o.str();
    s += d;
    return(*this);
  }
  append_to_string_with_delim &operator*()
  {
    return(*this);
  }
  append_to_string_with_delim &operator++()
  {
    return(*this);
  }
  append_to_string_with_delim const &operator++(int)
  {
    return(*this);
  }
  std::string &s;
  char const *const d;
};

и используйте std :: copy:

std::vector<int> v;
std::string s("The v vector elements are: ");
...
copy(v.begin(), v.end(), append_to_string_with_delim(s, " "));
0 голосов
/ 11 января 2011

Это рабочий пример,

template<typename T>  
std::string JoinToString(const T& cont, const char* delim, std::string &str)
{
   std::stringstream s;
   T::const_iterator it= cont.begin();
   T::const_iterator last= cont.end();
   while(it != last)
   {
      s << (*it);
      ++it;
      s << delim;
      if (it == last)
         break;
   }
   return s.str() + str;
} 

int main()
{
   std::string s("String! ");
   std::vector<std::string> v(1, "String!, String!");
   std::cout << JoinToString(v, ", ", s) << "\n";

   std::list<std::string> l(1, "String!, String!");
   std::cout << JoinToString(l, ", ", s);
}

Есть несколько вещей, на которые стоит обратить внимание. Вы можете использовать template<template<class> class T, хотя это может вызвать проблемы, в зависимости от количества аргументов шаблона, которое имеет контейнер.

Я хотел бы отметить (для дальнейшего использования), если вы хотите подключить тип к шаблону класса, например std :: string как аргумент шаблона в std :: vector самое безопасное решение,

template<class T>
struct something
{
   typedef typename boost::mpl::apply<T, std::string>::type type;
};
something<std::vector<boost::mpl::placeholders::_1>>::type;  

Причина, по которой это безопаснее, чем использование template<template<class> class T, заключается в том, что он позволит больше настроек со стороны пользователя и будет работать с шаблонами классов с любым количеством аргументов / аргументов по умолчанию.

0 голосов
/ 11 января 2011

Ваше решение почти правильное. Просто сделай это:

template<typename Container >  
string JoinToString(const Container & cont, const string &delim)
{
    stringstream s;
    for (Container::const_iterator it = cont.begin(); it != cont.end(); it++ )
    {
            s<<(*it);
            if ( (it+1) != cont.end() )
                   s<<delim;
    }
    return s.str();
} 

Лучшей функцией было бы это:

template<typename FwdIt>  
string JoinToString(FwdIt from, FwdIt to, const string &delim)
{
    stringstream s;
    for (; from != to; from++ )
    {
        s<<(*from);
        if ( (from+1) != to )
            s<<delim;
    }
    return s.str();
}

Используя это, решите from и to, используя которые объедините элементы!

0 голосов
/ 11 января 2011

Взгляните на , удалите char из stringstream и добавьте некоторые данные

Такой функции не существует.

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