I try to understand how to use std::tolower...
#include <iostream>
#include <string>
#include <algorithm>
#include <locale>
int main()
{
std::string test = "Hello World";
std::locale loc;
for (auto &c : test)
{
c = std::tolower(c, loc);
}
std::transform(test.begin(), test.end(), test.begin(), ::tolower); // 1) OK
std::transform(test.begin(), test.end(), test.begin(), std::tolower); // 2) Cryptic compile error
std::transform(test.begin(), test.end(), test.begin(), static_cast<int(*)(int)>(std::tolower)); // 3) Cryptic compile error. Seems OK with other compilers though
return 0;
}
So:
Why ::tolower version is working?
Why std::tolower is not working in std::transform?
What static_cast<int(*)(int)>(std::tolower)) really is trying to do? Why
does it work with GCC and not with Visual Studio 2013?
How could I use std::lower in std::transform with Visual Studio 2013 then?
First off, note, that none of these approaches does the right thing in a portable way! The problem is that char may be signed (and typically is) but the versions of tolower() only accept positive values! That is you really want to use std::tolower() using something like this:
std::transform(test.begin(), test.end(), test.begin(),
[](unsigned char c) { return std::tolower(c); });
(or, of course, using a corresponding function object if you are stuck with C++03). Using std::tolower() (or ::tolower() for that matter) with a negative value results in undefined behavior. Of course, this only matters on platform where char is signed which seems, however, to be the typical choice.
To answer your questions:
When including <cctype> you typically get the various functions and types from the standard C library both in namespace std as well as in the global namespace. Thus, using ::tolower normally works but isn't guaranteed to work.
When including <locale>, there are two versions of std::tolower available, one as int(*)(int) and one as char(*)(char, std::locale const&). When using just std::tolower the compiler has generally no way to decide which one to use.
Since std::tolower is ambiguous, using static_cast<int(*)(int)>(std::tolower) disambiguates which version to use. Why use of static_cast<...>() with VC++ fails, I don't know.
You shouldn't use std::tolower() with a sequences of chars anyway as it will result in undefined behavior. Use a function object using std::tolower internally on an unsigned char.
It is worth noting that using a function object rather than a function pointer is typically a lot faster because it is trivial to inline the function object but not as trivial to inline the function pointer. Compilers are getting better with inlining the use of function pointers where the function is actually known but contemporary compilers certainly don't always inline function calls through function pointers even if all the context would be there.
std::tolower is overloaded in C++, it's declared in <cctype> as
int tolower(int);
and also in <locale> as
template<CharT> CharT tolower(CharT, const locale&);
so when you say "std::tolower" you get an ambiguous reference to an overloaded function.
Why ::tolower version is working?
When you include <cctype> the one-argument overload is declared in namespace std and might also be declared in the global namespace, depending on the compiler. If you include <ctype.h> then it's guaranteed to be included in the global namespace, and ::tolower will work (although note Dietmar's points about when it's not safe). The two-argument overload from <locale> is never declared in the global namespace, so ::tolower never refers to the two-argument overload.
2. Why std::tolower is not working in std::transform?
See above, it's an overloaded name.
3. What static_cast<int(*)(int)>(std::tolower)) really is trying to do?
It tells the compiler you want the int std::tolower(int) overload, not any other overload of std::tolower.
Why does it work with GCC and not with Visual Studio 2013?
Probably because you didn't include <cctype>, or (less likely) it could be a Visual Studio bug.
4. How could I use std::lower in std::transform with Visual Studio 2013 then?
If you know you only have characters with values between 0 and 127 then you can include <ctype.h> and use ::tolower (because the two-argument version is not declared in the global namespace, only in namespace std) or disambiguate which overload you want with the static cast. An alternative to the cast is to use a local variable:
typedef int (*tolower_type)(int);
tolower_type tl = &std::tolower;
std::transform(b, e, b, tl);
A safer and portable alternative is to use a custom function object (or lambda expression) to call the desired overload safely:
std::transform(b, e, b, [](unsigned char i) { return std::tolower(i); });
This uses std::tolower with an argument, so the compiler can do overload resolution to tell which overload you want to call. The parameter is unsigned char to ensure we never pass a char with a negative value to tolower(int), because that has undefined behaviour.
See http://gcc.gnu.org/onlinedocs/libstdc++/manual/strings.html#strings.string.simple for more details.
Related
This code compiles successfully, and that's because I am apparently using the "global namespace" version of tolower (as opposed to either of the versions that live in <cctype> or <locale>) actually i'm not sure?.
#include <string>
#include <algorithm>
int main() {
std::string x = "FOO";
std::transform(x.begin(), x.end(), x.begin(), tolower);
}
My questions:
1) Where/how is this tolower established exactly?
2) Can someone direct me to a list of all such "global namespace" functions?
I've actually spent a fair amount of time seeking an answer; apologies if this is obvious knowledge and I missed it.
Some compilers provide declarations from <c__> headers (from C standard library) in both std:: and global namespace. As #chris said, this is allowed by the standard, but there are no guarantees. Thus, you should not rely on it.
I did exactly what was written here: Easiest way to convert int to string in C++
But I get an error at the std of std::to_string
#include <iostream>
#include <string>
int main()
{
std::string s = std::to_string(42);
return 0;
}
The error message you get can't be generated for a standard-conforming library implementation.
So, the best solution is to upgrade the compiler (presumably it's some years old Visual C++).
An alternative is to use an argument of type long, and hope that that's one of the existing overloads:
std::to_string( 42L )
I'm playing around with my coding style. I used to explicitly prefix every library call with std:: but I'm switching over to using declarations like this:
using std::count;
using std::vector;
One thing I've noticed over the past few days is that sometimes if I forget a using declaration -- using std::vector; is a good example -- I get reams of compiler errors. However, if I neglect to namespace delcare an algorithm such as using std::count; my code compiles just fine.
Does this have to do with the difference with classes and free functions? On all the reference sites, both count(first, last, value) and vector are prefixed with std:: so I would expect them to behave the same.
Or does it have to do with other functions in the global namespace? I notice std::max also seems to require a namespace declaration, perhaps it defined in a default-included Apple/glibc/LLVM file and thus there is a conflict if I used it sans namespace declaration?
I am using Apple LLVM 7.0.2. on El Capitan.
EDIT: Show us the code
#include <algorithm>
#include <vector>
using std::count;
using std::vector;
int main() {
vector<int> v = { 1, 2, 3, 4 };
return count(begin(v), end(v), 3);
}
As T.C. (almost) said, the magic incantation is ADL, which stands for "argument-dependent lookup". When a function is called with an argument whose type is defined in a namespace, the compiler looks for the function in that same namespace. Makes, sense, right?
I'm working on a C++ program for class, and my compiler is complaining about an "ambiguous" function call. I suspect that this is because there are several functions defined with different parameters.
How can I tell the compiler which one I want? Aside from a case-specific fix, is there a general rule, such as typecasting, which might solve these kinds of problems?
Edit:
In my case, I tried calling abs() inside of a cout statement, passing in two doubles.
cout << "Amount is:" << abs(amountOrdered-amountPaid);
Edit2:
I'm including these three headers:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
Edit3:
I've finished the program without this code, but in the interest of following through with this question, I've reproduced the problem. The verbatim error is:
Call to 'abs' is ambiguous.
The compiler offers three versions of abs, each taking a different datatype as a parameter.
What's happened is that you've included <cstdlib> (indirectly, since it's included by iostream) along with using namespace std;. This header declares two functions in std with the name abs(). One takes and returns long long, and the other returns long. Plus, there's the one in the global namespace (that returns int) that comes from <stdlib.h>.
To fix: well, the abs() that takes double is in <cmath>, and that will actually give you the answer you want!
The abs function included by <cstdlib> is overloaded for int and long and long long. Since you give a double as the argument, the compiler does not have an exact fit, so it tries to convert the double to a type that abs accepts, but it does not know if it should try to convert it to int, long, or long long, hence it's ambiguous.
But you probably really want the abs that takes a double and returns a double. For this you need to include <cmath>. Since the double argument matches exactly, the compiler will not complain.
It seems that <cstdlib> gets included automatically when you include the other headers which should not happen. The compiler should have given error: ‘abs’ was not declared in this scope or something similar.
Try using fabs defined in <cmath>. It takes float, double and long double as arguments. abs is defined both in <cmath> and <cstdlib>. The difference is abs(int), abs(long) and abs(long long) are defined in <cstdlib> while other versions are defined in <cmath>.
Not sure why this isn't calling the int version of abs but you could try type casting the expression (amountOrdered - amountPaid) as int i.e.
cout <<"Amount is: "<< abs( (int)(amountOrdered - amountPaint) );
//for( unsigned int i=0; i < c.size(); i++ ) tolower( c[i] );
for_each( c.begin(), c.end(), tolower );
I am trying to use a for_each loop in place of the for loop for an assignment.
I am unsure why I am getting this error message:
In function âvoid clean_entry(const std::string&, std::string&)â:
prog4.cc:62:40: error: no matching function for call to âfor_each(std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)â
Write:
for_each( c.begin(), c.end(), ::tolower );
Or :
for_each( c.begin(), c.end(), (int(*)(int))tolower);
I've faced this problem so many times that I'm tired of fixing this in my code, as well as in others' code.
Reason why your code is not working : there is another overloaded function tolower in the namespace std which is causing problem when resolving the name, because the compiler is unable to decide which overload you're referring to, when you simply pass tolower 1. That is why the compiler is saying unresolved overloaded function type in the error message, which indicates the presence of overload(s).
So to help the compiler in resolving to the correct overload, you've to cast tolower as
(int (*)(int))tolower
then the compiler gets the hint to select the global tolower function, which in other ways, can be used by writing ::tolower.
1. I guess you've written using namespace std in your code. I would also suggest you to not to do that. Use fully-qualified names in general.
By the way, I think you want to transform the input string into lower case, if so, then std::for_each wouldn't do that. You've to use std::transform function as:
std::string out;
std::transform(c.begin(), c.end(), std::back_inserter(out), ::tolower);
//out is output here. it's lowercase string.
1) You have using namespace std; somewhere in your code. The danger of importing the entire std namespace is that you don't necessarily know what you are getting. In this case, you have imported overloads of std::tolower.
Never type using namespace std;, even if your textbook or your instructor tells you to.
2) Since you are restricted from using std::transform, you could modify the string in place using std::for_each:
#include <cctype>
#include <algorithm>
#include <string>
#include <iostream>
void
MakeLower(char& c)
{
c = std::tolower(c);
}
int
main ()
{
std::string c("Hello, world\n");
std::for_each(c.begin(), c.end(), MakeLower);
std::cout << c;
}