3

While researching, I found Why “transform(s.begin(),s.end(),s.begin(),tolower)” can't be complied successfully? , and the solution is to use ::tolower. As an exercise, I want to see if I can disable that (in locale header file) overload and use std::tolower. First, we start simple:

template <typename charT> charT tolower(charT c, std::locale const& loc) = delete;

int main()
{
    std::vector<char> chars = { 'a', 'D', 'c', 'b' };
    std::transform(chars.begin(), chars.end(), chars.begin(), std::tolower);
}

The compiler cannot deduce the correct overload. So we provide the char template:

std::transform(chars.begin(), chars.end(), chars.begin(), std::tolower<char>);

So we're back to square one. I know it is undefined behavior, but I thought I could put it into namespace std:

namespace std {
template <typename charT> charT tolower(charT c, std::locale const& loc) = delete;
}

Now the compiler says I'm redefining the function.

using std::tolower;
template <typename charT> charT tolower(charT c, std::locale const& loc) = delete;

doesn't work either.

Now this is pointless exercise, but is this possible?

Community
  • 1
  • 1
user4320030
  • 158
  • 5
  • Explicitly deleting a function doesn't remove it from overload resolution; it just means you get an error if that overload is chosen. – Sebastian Redl Dec 03 '14 at 14:23

1 Answers1

6

You can't disable the other overload, but there are lots of ways to ensure the correct one is chosen:

int (*lower)(int) = std::tolower;
std::transform(chars.begin(), chars.end(), chars.begin(), lower);

or

std::transform(chars.begin(), chars.end(), chars.begin(), static_cast<int(*)(int)>(std::tolower));

or

std::transform(chars.begin(), chars.end(), chars.begin(), [](int c) { return std::tolower(c); });

or

struct ToLower {
  int operator()(int c) const { return std::tolower(c); }
};
std::transform(chars.begin(), chars.end(), chars.begin(), ToLower{});

The first two forms tell the compiler how to choose the right overload from the overload set, because only one of the overloads can be converted to a function pointer of that type.

The second two forms create a wrapper that invokes tolower so that normal overload resolution finds the right one, and you don't need to take the address of tolower.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521