Why Can't "Transform(S.Begin(),S.End(),S.Begin(),Tolower)" Be Complied Successfully

Why can't transform(s.begin(),s.end(),s.begin(),tolower) be complied successfully?

Try using ::tolower. This fixed the problem for me.

What's going on at tolower?

You can see this answered in my answer, that's a function pointer. You can read more about them here: http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_functions

Fundamentally this is a pointer to a function that takes in an int argument and returns an int.


The reason the transform works when using myToLower and not with an uncast tolower, is that in code is that the tolower function is overloaded in the std namespace by both the locale library's tolower and the ctype library's tolower. When only the function name is used as an uncast pointer no overload resolution is performed, and you'll get an error. When you cast the function pointer you're telling the compiler which overload you want.

Disable unwanted overload for tolower

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.

Which tolower in C++?

It should be noted that the language designers were aware of cctype's tolower when locale's tolower was created. It improved in 2 primary ways:

  1. As is mentioned in progressive_overload's answer the locale version allowed the use of the facet ctype, even a user modified one, without requiring the shuffling in of a new LC_CTYPE in via setlocale and the restoration of the previous LC_CTYPE
  2. From section 7.1.6.2[dcl.type.simple]3:

It is implementation-defined whether objects of char type are represented as signed or unsigned quantities. The signed specifier forces char objects to be signed

Which creates an the potential for undefined behavior with the cctype version of tolower's if it's argument:

Is not representable as unsigned char and does not equal EOF

So there is an additional input and output static_cast required by the cctype version of tolower yielding:

transform(cbegin(foo), cend(foo), begin(foo), [](const unsigned char i){ return tolower(i); });

Since the locale version operates directly on chars there is no need for a type conversion.

So if you don't need to perform the conversion in a different facet ctype it simply becomes a style question of whether you prefer the transform with a lambda required by the cctype version, or whether you prefer the locale version's:

use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), size(foo)));

Why is std::find( s.begin(), s.end(), val ) 1000x slower than s.find(val) for a setint s?

std::find is a generic algorithm that given a pair of iterators can find a value. And if all it has been given is a pair of iterators the best way to find a value is just to linearly search for it which is O(n).

set::find is a member function of std::set and so it knows the data structure its searching over and so can optimise the search. And sorted, balanced trees have excellent searching behavoir of O(log(n))

Web Config Transform not working

The Web.config transforms are only applied as part of a publish operation.

If you wish this to be done as part of an app.config build operation, then you can use the SlowCheetah - XML Transforms Visual Studio plugin:

http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5

How to convert an instance of std::string to lower case

Adapted from Not So Frequently Asked Questions:

#include <algorithm>
#include <cctype>
#include <string>

std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
[](unsigned char c){ return std::tolower(c); });

You're really not going to get away without iterating through each character. There's no way to know whether the character is lowercase or uppercase otherwise.

If you really hate tolower(), here's a specialized ASCII-only alternative that I don't recommend you use:

char asciitolower(char in) {
if (in <= 'Z' && in >= 'A')
return in - ('Z' - 'z');
return in;
}

std::transform(data.begin(), data.end(), data.begin(), asciitolower);

Be aware that tolower() can only do a per-single-byte-character substitution, which is ill-fitting for many scripts, especially if using a multi-byte-encoding like UTF-8.



Related Topics



Leave a reply



Submit