Problem
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.
Solution
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 strings.
Example 4-13. Join a sequence of strings
#include
#include
#include
using namespace std;
void join(const vector& v, char c, string& s) {
s.clear( );
for (vector::const_iterator p = v.begin( );
p != v.end( ); ++p) {
s += *p;
if (p != v.end( ) - 1)
s += c;
}
}
int main( ) {
vector v;
vector 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 << '
';
}
Discussion
Example 4-13 has one technique that is slightly different from previous examples. Look at this line:
for (vector::const_iterator p = v.begin( );
The previous string examples simply used iterators, 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 void joing(const std::vector >& v, T c, std::basic_string& s)
But vectors may not be your only input. You may be saddled with the task of joining an array of C-style strings. C++ strings 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
#include
const static int MAGIC_NUMBER = 4;
template
void join(T* arr[], size_t n, T c, std::basic_string& 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);
}
Building C++ Applications
Code Organization
Numbers
Strings and Text
Dates and Times
Managing Data with Containers
Algorithms
Classes
Exceptions and Safety
Streams and Files
Science and Mathematics
Multithreading
Internationalization
XML
Miscellaneous
Index