2
votes

I'm trying to convert the lowercase characters of a string into its uppercase counterpart using the std::toupper function and I'm using the std::for_each algorithm to iterate over the characters in the string.

#include <iostream>
#include <string>
#include <algorithm>
#include <locale>

std::string convert_toupper(std::string *x) {
  return std::toupper(*x, std::locale());
}

int main() {
  std::string x ("example");

  std::for_each(x.begin(), x.end(), convert_toupper);
}

When I compile this code I'm getting this error:

In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from me2.cpp:3:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; _Funct = std::basic_string<char> (*)(std::basic_string<char>*)]’:
me2.cpp:13:52:   required from here
/usr/include/c++/4.8/bits/stl_algo.h:4417:14: error: invalid conversion from ‘char’ to ‘std::basic_string<char>*’ [-fpermissive]
  __f(*__first);
              ^

What is the proper way of character conversion from lowercase to uppercase using std::toupper and std::for_each?

3

3 Answers

5
votes

A string is a container of chars, basically. When you iterate of a string, you are going one char at a time. So the functor you pass into for_each will be called with a char, not a string*, hence the error:

invalid conversion from ‘char’ to ‘std::basic_string<char>*

The correct implementation would just be:

std::for_each(x.begin(), x.end(), std::toupper);

That, however, would do nothing. The return value of toupper would be ignored, and that function has no side effects. If you really wanted to actually transform the string into its upper case version, you would have to use std::transform:

std::transform(x.begin(), x.end(), x.begin(), std::toupper);

Or, to provde locale:

char locale_upper(char c) { return std::toupper(c, std::locale()); }
std::transform(x.begin(), x.end(), x.begin(), locale_upper);

Or, in C++11:

std::transform(x.begin(), x.end(), x.begin(), [](char c){
    return std::toupper(c, std::locale());
});

At which point you might as well just use a for-loop:

for (char& c : x) {
    c = std::toupper(c, std::locale());
}
0
votes

In <locale> you already have the std::ctype::toupper function transforming lowercase strings in uppercase. The function call is a bit tricky but it is very compact:

std::use_facet<std::ctype<char>>(std::locale()).toupper(&x[0], &x[0] + x.size());
0
votes

Here is one way to convert a lowercase string to uppercase using std::for_each and std::toupper. The important thing is to remember to make the parameter in the lambda a char reference ie (char& ch).

#include <algorithm>   // for_each
#include <cctype>      // toupper
#include <iostream>    // cout
#include <string>      // string

int main()
{
   std::string s{ "This is a test" };
   std::cout << s << '\n';
   
   std::for_each(s.begin(), s.end(),[] (char& ch) { ch = std::toupper(ch); } );   
      
   std::cout << s << '\n';
   return 0;
}