gda2004
gda2004

Reputation: 746

c++ for each vector of strings

    typedef std::vector<std::string> TVector;
    TVector a_list;

    populate vector...
    for_each(a_list.begin(),a_list.end(),std::toupper);

error

no matching function for call to 'for_each(std::vector<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >::iterator, <unresolved overloaded function type>)

Do I need to iterate over the elements using the a standard for loop ? Or is there another way I am not allowed to use c++ 11 features.

Thanks

Upvotes: 3

Views: 1701

Answers (3)

Jon Purdy
Jon Purdy

Reputation: 54971

std::toupper is an overloaded function; that’s why you’re getting <unresolved overloaded function type> in the error message. To select a particular overload, you need to cast it:

static_cast<int(*)(int)>(std::toupper)

for_each is also not the right choice for this task—it will call toupper for each string in the list, then discard the result. std::transform would be the appropriate choice—it writes its output to an output iterator. However, toupper works on characters, not strings. You could still use transform to call toupper for each character in a string:

std::transform(
    a_string.begin(),
    a_string.end(),
    a_string.begin(),
    static_cast<int(*)(int)>(std::toupper)
);

It would probably be clearer in this simple case to use loops:

for (TVector::iterator i = a_list.begin(), end = a_list.end(); i != end; ++i) {
    for (std::string::size_type j = 0; j < i->size(); ++j) {
        (*i)[j] = toupper((*i)[j]);
    }
}

But if you wanted to write it with <algorithm> and <iterator> tools only, you could make a functor:

struct string_to_upper {
    std::string operator()(const std::string& input) const {
        std::string output;
        std::transform(
            input.begin(),
            input.end(),
            std::back_inserter(output),
            static_cast<int(*)(int)>(std::toupper)
        );
        return output;
    }
};

// ...

std::transform(
    a_list.begin(),
    a_list.end(),
    a_list.begin(),
    string_to_upper()
);

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409166

The toupper function is used for characters, not strings. It also returns the uppercase character, so won't work with for_each, but will with std::transform. There is also the problem that std::toupper exists in two overloads, and the compiler can't decide which one to use. Include <cctype> and use plain toupper (or optionally ::toupper) to get the right function.

You need to iterate first over all strings in the vector, and the iterate again over the string to call toupper.

You can either do it manually, or use transform and use functor objects, something like

struct strtoupper
{
    std::string operator()(const std::string& str) const
    {
        std::string upper;
        std::transform(str.begin(), str.end(), std::back_inserter(upper), ::toupper);
        return upper;
    }
};

// ...

std::transform(a_list.begin(), a_list.end(), a_list.begin(), strtoupper());

Upvotes: 4

Asha
Asha

Reputation: 11232

You have a vector of std::string and std::toupper expects a char as parameter. So it can not be used. What you can do is:

std::for_each(list.begin(), list.end(),[](std::string& s) { std::for_each(s.begin(), s.end(), std::toupper);});

Upvotes: 3

Related Questions