Design Improvements
There are ways to further benefit from using transform(). Suppose you need to transform a string to lowercase rather than uppercase. You change the transform() call to:
std::transform(s.begin(),
s.end(),
std::back_inserter(s1),
std::tolower);
It's not much of an improvement compared to the original for loop, is it? To avoid intrusive code changes such as this, use an additional level of indirection. Instead of passing a function's name as an argument, use a pointer to a function. This way, you can decouple the transform() call from the customers' requirements. Furthermore, the use of a pointer enables you to postpone the function binding to runtime:
int (*pf)(int)=tolower;
transform(s.begin(), s.end(), s.begin(), pf);
//lowercase
Notice that you don't need to change the transform() call now if you wish to apply yet another transformation:
pf=tocyrillic; // just an example
transform(s.begin(), s.end(), s.begin(), pf);
// Cyrillic
Conclusions
If using transform() to convert a string to uppercase seems like overkill to you, you're probably right. The string transformation was a red herring, though. The point was to show how to use transform() to manipulate sequences in a generic fashion. By using transform(), transforming a sequence of integers to their negative or square root values is a cinch:
template <class T> class negate
{
public:
T operator()(T t) { return -t;}
};
int arr[]={1, 2, 3};
transform(arr,
arr+sizeof(arr)/sizeof(int),
arr,
negate<int>()); // arr = {-1, -2, -3}