Given a sequence of strings, such as output from Example 4-10, you want to join them together into a single, long string, perhaps with a delimiter.
Loop through the sequence and append each string to the output string. You can handle
any standard sequence as input; Example
4-13 uses a vector
of string
s.
Example 4-13. Join a sequence of strings
#include <string> #include <vector> #include <iostream> using namespace std; void join(const vector<string>& v, char c, string& s) { s.clear(); for (vector<string>::const_iterator p = v.begin(); p != v.end(); ++p) { s += *p; if (p != v.end() - 1) s += c; } } int main() { vector<string> v; vector<string> v2; string s; v.push_back(string("fee")); v.push_back(string("fi")); v.push_back(string("foe")); v.push_back(string("fum")); join(v, '/', s); cout << s << '\n'; }
Example 4-13 has one technique that is slightly different from previous examples. Look at this line:
for (vector<string>::const_iterator
p = v.begin();
The previous string examples simply used iterator
s,
without the “const” part, but you can’t get away with that here because v
is declared as a reference to a const
object. If you have a const
container object, you can only use a const_iterator
to
access its elements. This is because a plain iterator
allows writes to the object it refers to, which, of course, you can’t do if your container
object is const
.
I declared v
const
for two reasons. First, I know I’m not going to
be modifying its contents, so I want the compiler to give me an error if I do. The
compiler is much better at spotting that kind of thing than I am, especially since a
subtle syntactic or semantic error can cause an unwanted assignment. Second, I want to
advertise to consumers of this function that I won’t do anything to their container, and
const
is the perfect way to do that. Now, I just have
to create a generic version that works on multiple character types.
Just as in Recipe 4.6, making
join
generic with a function template is easy. All
you have to do is change the header to be parameterized on the type of character, like
this:
template<typename T> void joing(const std::vector<std::basic_string<T> >& v, T c, std::basic_string<T>& s)
But vector
s may not be your only input. You may be
saddled with the task of joining an array of C-style strings. C++ string
s are preferable to C-style strings, so if you have to do this, join
them into a C++ string
. Once you’ve done that, you can
always retrieve a C-style version by calling string
’s
c_str
member function, which returns a const
pointer to a null-terminated character array.
Example 4-14 offers a generic version
of join
that joins an array of character arrays into a
string
. Since the new, generic version is
parameterized on the character type, it will work for narrow or wide character
arrays.
Example 4-14. Joining C-style strings
#include <string> #include <iostream> const static int MAGIC_NUMBER = 4; template<typename T> void join(T* arr[], size_t n, T c, std::basic_string<T>& s) { s.clear(); for (int i = 0; i < n; ++i) { if (arr[i] != NULL) s += arr[i]; if (i < n-1) s += c; } } int main() { std::wstring ws; wchar_t* arr[MAGIC_NUMBER]; arr[0] = L"you"; arr[1] = L"ate"; arr[2] = L"my"; arr[3] = L"breakfast"; join(arr, MAGIC_NUMBER, L'/', ws); }
Get C++ Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.