5

I'm using transform algorithm and std::toupper to achieve this, but can this be done in one line, like this ?

transform(s.begin(), s.end(), ostream_iterator<string>(cout, "\n"),std::toupper);

I get error on this, so do I have to make a unary function for this and call it with transform or I can use some adaptors ?

pavium
  • 14,808
  • 4
  • 33
  • 50
Adrian
  • 19,440
  • 34
  • 112
  • 219
  • 1
    It is important to post the actual error that you are getting. In particular in a comment to the accepted answer you have added that error, and that in turn says that the problem is with overload resolution. At that point, with all the information, people can come up with a clear explanation of what the problem is and different ways to solve it, rather than just a work around that will not help you with the next similar problem (overload resolution when using a function in a template) – David Rodríguez - dribeas May 11 '11 at 11:17
  • yeah, i forgot about the error, sorry – Adrian May 11 '11 at 11:31

2 Answers2

9

Use ostream_iterator<char> instead of ostream_iterator<string>:

transform(s.begin(),s.end(),ostream_iterator<char>(cout,"\n"),std::toupper);

std::transform transforms each character and pass it to the output iterator. That is why the type argument of the output iterator should be char instead of std::string.

By the way, each character will be printed on a newline. Is that what you want? If not, don't pass "\n".

--

Note : You may have to use ::toupper instead of std::toupper.

See these

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I see what you mean, but I get the same error with char to :-/ – Adrian May 11 '11 at 11:03
  • error: no matching function for call to 'transform(std::basic_string::iterator, std::basic_string::iterator, std::ostream_iterator, )' – Adrian May 11 '11 at 11:04
  • @vBx: You may have to use `::toupper` instead of `std::toupper`. See the edit and the demo. – Nawaz May 11 '11 at 11:05
  • Be aware that it's undefined behavior to pass a negative number to `::toupper`. – Steve Jessop May 11 '11 at 11:43
  • @vBx Or seems to. It's undefined behavior (although some implementations go out of their way to make it work, most of the time). As a test string, you might want to try `"L'Haÿ"` (the name of a suburb of Paris); this should result in `"L'HAŸ"`, but probably won't if plain `char` is signed (the default on most systems). – James Kanze May 11 '11 at 11:47
  • [Don't use `::toupper`.](http://stackoverflow.com/questions/7131858/stdtransform-and-toupper-no-matching-function/7132065#7132065) – Lightness Races in Orbit Oct 07 '11 at 09:11
4

First, if you want to output chars (and all of the chars), you'll need to use ostreambuf_iterator<char>, and not ostream_iterator<string>. And ostreambuf_iterator<char> expresses better what you want than ostream_iterator<char>; you're outputting chars directly, not formatting anything. (ostream_iterator uses the << operator, which formats.)

Second, be aware that there is not always a one to one translation of lower to upper (e.g. 'ß' maps to the two character sequence "SS" in upper case), so std::transform can't really be used to do the job correctly. (And of course, it doesn't handle multibyte encodings like UTF-8 correctly.) For all but the simplest uses, you need something more complicated. But even for the simplest cases:

std::toupper is overloaded: one of the overloads is a template, which takes two arguments, and the other is a function which takes a single int; neither will work directly here, and the fact that transform is also a template means that overload resolution and template type deduction won't work even if they did. So basically, you have to add something. It's possible to use the 2 argument template function if you add enough qualifiers and use boost::bind or something similar to bind the second argument, but it's almost as much text as writing a simple toupper functional argument your self. And you can't use the single argument form (which can be unambiguously accessed if you include <ctype.h> and use ::toupper) because it has undefined behavior if you use a char as the argument when you call it: you have to convert the char to unsigned char first (unless, of course, plain char is unsigned in the implementation you are using—and in all implementations to which your code will ever be ported).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • +1, This does actually tackle the issue in the question, rather than blindly proposing changes. For a simple solution that uses the `int toupper(int)` you only need a cast in the last argument: `std::transform( ..., (int (*)(int)) std::toupper );`, as that will resolve the overload: only one of the `toupper` overloads can be casted to that particular function signature. – David Rodríguez - dribeas May 11 '11 at 11:49
  • @David The problem is that using `int toupper(int)` results in undefined behavior; you don't want to use it directly. – James Kanze May 11 '11 at 12:04