如何在具有迭代器的stl容器上模板化一个函数

时间:2011-01-11 12:48:17

标签: c++ templates

我想写一个带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 个答案:

答案 0 :(得分:7)

STL样式是将beginend迭代器传递给任何算法,而不是容器本身:这使事情保持一般,并允许使用带指针的本机向量。一般的C ++样式注意事项也建议返回std::string而不是使用引用参数。

答案 1 :(得分:1)

你需要决定你想要什么。您可以传递类型或模板。不是都。在您发布的代码中,您将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; } 

答案 2 :(得分:1)

如果你真的需要访问容器,那么这将做你想要的:

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)
  {
     ...
  }
}

答案 3 :(得分:1)

另一种完全符合您要求的解决方案是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

答案 4 :(得分:0)

查看remove char from stringstream and append some data

这样的功能不存在。

答案 5 :(得分:0)

您的解决方案几乎是正确的。就这样做:

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();
}

使用此决定fromto使用哪个来加入元素!

答案 6 :(得分:0)

这是一个有效的例子,

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更安全的原因是,它允许从用户端进行更多自定义,并且可以使用任意数量的参数/默认参数来处理类模板。

答案 7 :(得分:0)

创建自定义输出迭代器:

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, " "));