2011-01-11 40 views
1

我想編寫一個函數,它將採用stl容器(如集合,向量或列表) ,然後遍歷內容,然後將它們附加到字符串並返回字符串。如何在具有迭代器的stl容器上模擬函數

就是這樣。

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

我想要這個效果。不知道如何編寫這樣的代碼。

回答

1

你需要決定你想要什麼。您可以傳遞一個類型或模板。不是都。在您發佈的代碼中,您聲明Container爲類型,但將其用作模板。

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

傳遞模板並不是微不足道的。對於初學者來說,你的代碼在所有的標準編譯器中都會失敗,因爲`std :: vector`容器至少需要兩個類型參數。然後問題是標準允許實現只要默認就添加額外的參數,也就是說,在一個完全符合的實現中,`std :: vector`可以有3,4,5 ...個參數。 – 2011-01-11 13:06:22

+0

模板模板參數很難使用和維護,並且出於各種原因,包括David指出的,它們不會增加太多。我從來沒有覺得需要達到一個生產代碼。 – 2011-01-11 13:43:42

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使用其加入的元素!

+0

嘗試了第一個解決方案,但沒有編譯。我正在嘗試Linux。它說預計';'在它和'它'沒有在這個範圍內聲明 – AMM 2011-01-11 14:28:32

+0

@AMM:我想,你正在編譯的代碼與我在這裏寫的不完全相同。請檢查出它是否一致,一行一行,用分號分號! – Nawaz 2011-01-11 15:16:47

7

STL樣式是將beginend迭代器傳遞給任何算法,而不是容器本身:這將保持一般性,並允許使用帶指針的本地向量。一般的C++風格考慮也會建議返回std::string而不是使用參考參數。

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) 
    { 
    ... 
    } 
} 
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 ::向量最安全的辦法是,

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是,它將使更多的定製從用戶側並將使用任何數量的參數/默認參數在類模板上工作。

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

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 ::副本:

std::vector<int> v; 
std::string s("The v vector elements are: "); 
... 
copy(v.begin(), v.end(), append_to_string_with_delim(s, " "));