To transform a string and make it lowercase, we might do the following:
#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
using namespace std;
int main()
{
string str("Sample STRING");
cout << str << endl;
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
cout << str << endl;
return 0;
}
I know what std::transform is all about; but what's the scope operator :: doing in front of the function tolower?
If I remove the scope operator then the compiler complains of a function mismatch. If I add std in front of the :: operator then the compiler also complains of a function mismatch. What is the purpose of the scope operator in front of tolower? I don't know what it's called, and I searched everywhere for an explanation but to no avail.
You should #include <algorithm> to use std::transform.
The tolower function you want is defined in ctype.h or cctype. You should include one of these headers. The former declares tolower in the global namespace; the latter declares it in the std namespace.
It's likely that without the ::, you're picking up the function template std::tolower declared in the <locale> header. Of course, this only happens because you have using namespace std;. This is a particular example of how using namespace std; can be dangerous.
The :: with nothing on the left means the name to the right will be "looked up in global scope" and will find the global tolower rather than std::tolower. (Therefore, you should #include <ctype.h> to make sure you get the global declaration.)
:: without a left side bypasses looking in all accessible sub-scopes and forces the use of the root (or global) scope.
Related
#include <iostream>
#include <string>
#include <cctype>
using std::string;
using std::cin;
using std::cout; using std::endl;
int main()
{
string s("Hello World!!!");
decltype(s.size()) punct_cnt = 0;
for (auto c : s)
if (ispunct(c))
++punct_cnt;
cout << punct_cnt
<< " punctuation characters in " << s << endl;
}
It seems that I can use ispunct() without std:: or declaring using std::ispunct; but I can't do that with std::cout or std::cin. Why is this happening?
It means ispunct is part of the global namespace, rather than the std namespace. This is probably because ispunct is one of the functions brought over from C (hence it is in cctype).
On the other hand, cout and cin are part of the std namespace, not the global namespace.
Edit:
As to why things from C are in the global namespace instead of in the std namespace, I believe it has to do with allowing C code to compile by a C++ compiler with minimal changes, since C++ aims to be compatible with C.
According to the comments, ispunct is allowed, but not required, to be in the global namespace (but is required to be in the std namespace), in <cctype>. However, if you had included <ctype.h> instead, ispunct would be required to be in the global namespace.
C names (those you get from including a xxx.h header from C) are allowed to be in the global namespace in addition to the ::std namespace even if you are including the cxxx version of the header. This has been done because it can be a problem not to have those in the global namespace if you provide the C++ implementation, but not the C implementation (so the actual C headers are from a compiler you don't control).
In your case, ispunct comes from the header ctype.h. While you are including the cctype header, this in turn includes the ctype.h header which declares the symbol ispunct in the global namespace.
C++ headers derived from C (such as <cctype>) are required to put the names of things that they declare in the namespace std and they are permitted to also put them in the global namespace. Formally, this wasn't allowed until C++11, but the old rule that those headers were not allowed to put names into the global namespace could not be implemented reasonably and was commonly ignored.
Under some situations, it seems like I can access functions that should be in the std namespace without a using or std:: qualifier. So far, I've only seen this occur with functions from the algorithm library.
In the following example, I expect all_of() to be in the std namespace, but this code compiles without error in VS2013 (Microsoft Compiler 18).
#include <iostream>
#include <string>
#include <algorithm>
int main() {
const std::string text = "hey";
std::cout << all_of(begin(text),end(text),islower);
return 0;
}
Changing std::cout to cout without adding a using namespace std or using std::cout generates an "undeclared identifier" error as expected.
What's going on here?
This probably happens due to Argument-Dependent Lookup. The iterator returned by begin(text) and end(text) is probably a class defined in namespace std (or nested in a class in namespace std), which makes namespace std associated with it. Looking up unqualified names for function calls looks into associated namespaces, and finds all_of there.
By the way, this is exactly the same reason why calling begin(text) works, even though the function template begin() is defined in namespace std. text is a std::basic_string, so std is searched.
#include <iostream>
#include <string>
#include <cctype>
using std::string;
using std::cin;
using std::cout; using std::endl;
int main()
{
string s("Hello World!!!");
decltype(s.size()) punct_cnt = 0;
for (auto c : s)
if (ispunct(c))
++punct_cnt;
cout << punct_cnt
<< " punctuation characters in " << s << endl;
}
It seems that I can use ispunct() without std:: or declaring using std::ispunct; but I can't do that with std::cout or std::cin. Why is this happening?
It means ispunct is part of the global namespace, rather than the std namespace. This is probably because ispunct is one of the functions brought over from C (hence it is in cctype).
On the other hand, cout and cin are part of the std namespace, not the global namespace.
Edit:
As to why things from C are in the global namespace instead of in the std namespace, I believe it has to do with allowing C code to compile by a C++ compiler with minimal changes, since C++ aims to be compatible with C.
According to the comments, ispunct is allowed, but not required, to be in the global namespace (but is required to be in the std namespace), in <cctype>. However, if you had included <ctype.h> instead, ispunct would be required to be in the global namespace.
C names (those you get from including a xxx.h header from C) are allowed to be in the global namespace in addition to the ::std namespace even if you are including the cxxx version of the header. This has been done because it can be a problem not to have those in the global namespace if you provide the C++ implementation, but not the C implementation (so the actual C headers are from a compiler you don't control).
In your case, ispunct comes from the header ctype.h. While you are including the cctype header, this in turn includes the ctype.h header which declares the symbol ispunct in the global namespace.
C++ headers derived from C (such as <cctype>) are required to put the names of things that they declare in the namespace std and they are permitted to also put them in the global namespace. Formally, this wasn't allowed until C++11, but the old rule that those headers were not allowed to put names into the global namespace could not be implemented reasonably and was commonly ignored.
Why is getline() from header string in local scope and can be used:
#include <iostream>
#include <string>
int main() {
std::string str;
getline(std::cin, str);
std::cout << str << "\n";
return 0;
}
That works with gcc. But why? It is defined in header string, which should required me to use std::getline() instead of getline().
You're experiencing Argument Dependent Lookup (ADL, and also referred to as Koenig Lookup). Since one or more of the arguments is a type defined in the std namespace, it searches for the function in the std namespace in addition to wherever else it would search. I point you to Stephan T. Lavavej's video to learn more about it and name lookup in general.
when I'm reading some c++ sample code for beginner , I'm puzzled at the usage of toupper in the following line :
std::transform(data.begin(), data.end(), data.begin(), ::toupper);
from the above line, I know that "transform" is from namespace std , but I don't know which namespace does toupper come from . maybe there is a default namespace for c++ but
that is just my guess. so could you explain the usage of toupper here to me ?
If you include
<cctype>
then toupper() is in namespace std. If you include
<ctype.h>
then toupper() is in the global namespace. (The one everything ends up in if not defined in a specific namespace. The one you refer to with a leading :: when you're in a specific namespace.)
The same rule applies to <cstring> vs. <string.h>, <cstdlib> vs. <stdlib.h> etc.
If you are puzzled from the ::toupper syntax, it is telling you that in this case, the function is in the global namespace. You can always prepend a double colon to a name and that will tell the compiler to check in the global namespace and not search from your inner namespace out.
void foo() { std::cout << "global"; }
namespace inner {
void foo() { std::cout << "inner"; }
void call() {
foo(); // prints inner
::foo(); // prints global
::inner::foo(); // prints inner (fully qualified namespace)
}
}