10

I know the answer to the frequently-asked How do I specify a pointer to an overloaded function?: Either with assignment or with a cast, and every other C++ tutorial uppercases a string like this (give or take static_cast):

transform(in.begin(), in.end(), back_inserter(out), (int(*)(int)) std::toupper);

Or like this:

int (*fp)(int) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp);

Which neatly selects the <cctype> overload of std::toupper.

But this begs the question: How can I select the <locale> overload in a similar manner?

char (*fp2)(char, const std::locale&) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp2);
// error: too few arguments to function

Or, more practically, consider someone trying to use the C++11 std::stoi in an algorithm to convert a vector of strings to a vector of integers: stoi has two overloads (string/wstring), each taking two additional default arguments.

Assuming I don't want to explicitly bind all those defaults, I believe it is impossible to do this without wrapping such call in an auxiliary function or lambda. Is there a boost wrapper or TMP magic to do it for me in completely generic manner? Can a wrapper like call_as<char(char)>(fp2) or, more likely, call_as<int(const std::string&)>(std::stoi) even be written?

Community
  • 1
  • 1
Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • 3
    Can you just use a lambda in your `transform` command? Easiest and cleanest. – Kerrek SB Jul 06 '11 at 22:19
  • I wrote and deleted a comment about `bind` already being the wrapper you were looking for. Then it occurred to me that you'd have to provide the default values to bind, thus re-defining them. – Merlyn Morgan-Graham Jul 06 '11 at 22:20
  • It's better to get the algorithm right before thinking about how to obfuscate the code via template stuff. So, start with algorithm. `std::toupper` call yields Undefined Behavior if there is a negative argument except `EOF` value. – Cheers and hth. - Alf Jul 07 '11 at 08:58
  • 1
    You can do `auto *x = std::toupper;`. That looks considerably shorter. – Johannes Schaub - litb Jul 07 '11 at 09:05

2 Answers2

5

It's funny, I was doing something similar. The best way I found to do it was using lambdas as follows, because otherwise, you have to use a typedef to get the right overload and a std::bind to get rid of the locale, or not use the locale. However, this works much more cleanly:

static const std::locale loc;
transform(in.begin(), in.end(), back_inserter(out), [&loc](char c) {
  return std::toupper(c, loc);
});

I use the static to save the effort of reallocating each time.

Or you could get a typedef and do:

 std::bind((LocaleCompare)std::toupper, std::placeholders::_1, loc); // UGLY!
sehe
  • 374,641
  • 47
  • 450
  • 633
norcalli
  • 1,215
  • 2
  • 11
  • 22
0

You could should create a typedef of that functon pointer type, and then cast the function.

typedef char (*LocaleToUpper)(char, const std::locale&) ;
char (*fp2)(char, const std::locale&) = (LocaleToUpper)toupper;
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185