我想写一个带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();
}
我想要一些这样的效果。不知道如何编写这样的代码。
答案 0 :(得分:7)
STL样式是将begin
和end
迭代器传递给任何算法,而不是容器本身:这使事情保持一般,并允许使用带指针的本机向量。一般的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)
答案 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();
}
使用此决定from
和to
使用哪个来加入元素!
答案 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, " "));