This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
unresolved overloaded function type c++
Consider the code snippet below:
#include <algorithm>
#include <cctype>
#include <string>
using namespace std;
void test(){
std::string str = "Hello World!";
std::transform(str.begin(), str.end(), str.begin(), tolower);
}
There is an error about tolower when compiling with G++: unresolved overloaded function.
If using namespace std; is removed, the code works fine.
Then, my questions are:
What is the relationship between namespace std with C functions?
What is the difference between #include<ctype.h> and #include<cctype>? Although both of them don't work in the example above.
Why std::tolower also doesn't work? What's the difference between std::tolower and tolower?
There is no relationship between namespace std and C functions. But
your code isn't C, it's C++, so you also have to consider C++ functions.
Like std::tolower, for example, in <locale>. Your problem is due to
a concurrence of things:
One of the headers you include includes <locale>. C++ headers are
allowed to include other C++ headers, and which header includes which
other header may vary from one implementation to the other, so the
code you've written might compile with one compiler, and not with
another.
You're trying to pass the function as a pointer to function argument,
to a function template where the argument is a template type
parameter. Simply put, in order to do overload resolution on
tolower here, the compiler must match it to the type of the
argument, and in order to know the type of the argument, the compiler
must do template type deduction based on the exact type of the
function, which it can only know once it has done overload resolution.
If you want the function in <ctype.h> (which you don't, since it would
result in undefined behavior), you can get it either by including
<ctype.h> (which guarantees that it is present in the global
namespace) and using ::tolower, or by explicitly specifying the
overload you want, e.g. static_cast<int (*)(int)>( tolower ) (In this
particular case, static_cast doesn't mean type conversion, but
explicit overload resolution.)
In practice, of course, you don't do this sort of thing. If you're
doing any text processing at all, you'll define all of the necessary
functions as functional object types, which avoid undefined behavior by
either converting the input to unsigned char:
struct ToLower
{
char operator()( char ch ) const
{
return ::tolower( static_cast<unsigned char>( ch ) );
}
};
or by using the functions in <locale> which do work with char:
class ToLower
{
std::locale myLocale; // necessary to guarantee the lifetime of the facet.
std::ctype const* myCType;
public:
ToLower( std::locale const& loc = std::locale() )
; myLocal( loc )
, myCType( &std::use_facet<std::ctype>( loc ) )
{
}
bool operator()( char ch ) const
{
return myCType->tolower( ch );
}
};
Finally, WRT your second question: the difference depends on the version
of C++ you're using and the compiler. Globally, however: <ctype.h>
will introduce the functions into the global namespace; <cctype> will
introduce them into the namespace std::, and maybe (or maybe not) into
the global namespace. (And your third question has already been
answered above: std::tolower refers to a set of overloaded functions
defined in <locale> and <cctype>; ::tolower refers to a single
function defined in <ctype.h>, and just tolower is the equivalent of
::tolower, unless you've done using namespace std, in which case,
it will refer to the overload set of all of the functions mentionned
above.
You can use the namespace operator to use the C version of tolower like this:
::tolower(); // nothing before '::' means look in the global namespaece.
This will force the compiler to look for a function that is not inside a specific namespace, which is the case for all C-based API.
As for why std::tolowerdoesn't work, I have no idea. The example of cpp reference doesn't use std::transform, this might be the reason.
Related
#include <iostream>
#include <cmath>
/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
return a > 0? -a : a;
}
int main() {
int a = abs(-5);
int b = std::abs(-5);
std::cout<< a << std::endl << b << std::endl;
return 0;
}
I expected that the output will be -5and 5, but the output is the -5 and -5.
I wonder why this case will happen?
Does it have anything to do with the use of std or what?
The language specification allows implementations to implement <cmath> by declaring (and defining) the standard functions in global namespace and then bringing them into namespace std by means of using-declarations. It is unspecified whether this approach is used
20.5.1.2 Headers
4 [...] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (6.3.6) of the namespace std. It is unspecified whether these names (including any overloads
added in Clauses 21 through 33 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (10.3.3).
Apparently, you are dealing with one of implementations that decided to follow this approach (e.g. GCC). I.e. your implementation provides ::abs, while std::abs simply "refers" to ::abs.
One question that remains in this case is why in addition to the standard ::abs you were able to declare your own ::abs, i.e. why there's no multiple definition error. This might be caused by another feature provided by some implementations (e.g. GCC): they declare standard functions as so called weak symbols, thus allowing you to "replace" them with your own definitions.
These two factors together create the effect you observe: weak-symbol replacement of ::abs also results in replacement of std::abs. How well this agrees with the language standard is a different story... In any case, don't rely on this behavior - it is not guaranteed by the language.
In GCC this behavior can be reproduced by the following minimalistic example. One source file
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Another source file
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In this case you will also observe that the new definition of ::foo ("Goodbye!") in the second source file also affects the behavior of N::foo. Both calls will output "Goodbye!". And if you remove the definition of ::foo from the second source file, both calls will dispatch to the "original" definition of ::foo and output "Hello!".
The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>. Implementations are allowed to simply include C-style <math.h>, then redeclare the functions in std and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.
Note that if we simply globally replace int with double in the above program, the code (under GCC) will behave "as expected" - it will output -5 5. This happens because C standard library does not have abs(double) function. By declaring our own abs(double), we do not replace anything.
But if after switching from int with double we also switch from abs to fabs, the original weird behavior will reappear in its full glory (output -5 -5).
This is consistent with the above explanation.
Your code causes undefined behaviour.
C++17 [extern.names]/4:
Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
So you cannot make a function with the same prototype as the Standard C library function int abs(int);. Regardless of which headers you actually include or whether those headers also put C library names into the global namespace.
However, it would be allowed to overload abs if you provide different parameter types.
Is it possible to redefine operator < for strings without modifying std namespace, to make this operator use in standard algorithms?
For example, I can write:
namespace std
{
bool operator <(const std::string & rhs, const std::string & lhs)
{
std::cout << "lol";
return false;
}
}
int main()
{
std::vector<std::string> lol = { "a", "b", "ba", "aa" };
std::sort(lol.begin(), lol.end());
}
and "lol" will be printed several times. But if I move operator < outside from std namespace, default operator < will be used and nothing will be printed. Is it possible to make std::sort using custom operator < without including it to std namespace?
Yes I know, I can pass another comparator to std::sort but it's interesting for me if I could do what I asked and how?
Also am I correct, that it's correct to add such template specialization to std namespace?
Update: This is not practical question, I just want to know how can I do that if it's possible.
No, it is not. Adding a function to the standard namespace is undefined behavior. [namespace.std]/1 states:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
If you want to change how std::sort sorts then you can provide a lambda and define what you want
std::sort(std::begin(foo), std::end(foo), [](const auto& lhs, const auto& rhs) { /* your code here */ });
Is it possible to redefine operator < for strings without modifiying std namespace
You can define the overload in another namespace, sure. But as you have found out, it will not be found by overload resolution unless explicitly qualified.
Is it possible to make std::sort using custom operator < without including it to std namespace?
Yes, and you already seem to know how:
Yes I know, I can pass another comparator to std::sort
This is exactly what the comparator argument is for.
Also am I correct, that it's corect to add such template specialization to std namespace?
That is not a template specialization; It is a function definition and you may not add function definitions to std namespace - or else the behaviour is undefined. You would be allowed to add template specializations, but only if at least one type argument is a user defined type.
struct int_holder {
int value;
int triple() {return value*3;}
};
int main(int argc, const char * argv[])
{
std::string abc{"abc"};
int_holder one{1};
auto f1 = mem_fn(&std::string::clear);
auto f2 = mem_fn(&int_holder::triple);
f1(abc);
f2(one);
}
i test such code in Xcode and the compiler issues such error
it seems mem_fn is fine with member functions of user-defined class but not with member functions of standard string, what's the different, and why?
thanks for your reading, help me plz!
I can reproduce this with Clang 3.1-3.3 as well as 3.6. Looks like bug 16478.
Simplest fix is to just use a lambda or equivalent. Other completely non-portable workarounds include either disabling extern templates with
#ifndef _LIBCPP_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...)
#endif
before you include any headers (in essence applying r189610); and doing an explicit instantiation of either the member function (template void std::string::clear();) or the entire class.
That said, you should not take the address of a member function of a standard library class. [member.functions]/p2:
An implementation may declare additional non-virtual member function
signatures within a class:
by adding arguments with default values to a member function signature;187
by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
by adding a member function signature for a member function name.
187) Hence, the address of a member function of a class in
the C++ standard library has an unspecified type.
As for the standard, you can't take a pointer to any standard nonstatic member because the library implementation is allowed to add hidden overloads, defaulted function template parameters, SFINAE in the return type, etc.
In other words, & std::string::clear is simply not a supported operation.
In terms of Clang, it looks like an issue with hidden symbol visibility. Each shared object (linker output) file gets its own copy of certain functions to avoid the appearance that third-party shared libraries implement the standard library. With different copies floating around, the equality operator over PTMFs would not work: If you retain the value & std::string::clear from an inline function, it might not compare equal to itself later. However, it's probably a bug, since std::string should be completely implemented by the libc++.so shared library. Only other specializations of std::basic_string could really justify this behavior.
A good fix would be to use a lambda instead. []( std::string & o ) { o.clear(); } is a superior alternative to mem_fn. It avoids the indirect call and its sizeof is smaller. Really, you shouldn't use mem_fn unless absolutely necessary.
When I'm switching the compiler version from gcc 4.6 to gcc 4.8 I get the following error
error: call of overloaded 'isnan(double)' is ambiguous.
This is because in c++11 there are differend function declarations:
C: int isnan(double)
C++11: bool isnan(double)
from cpluplus:
In C, this is implemented as a macro that returns an int value. The type of x shall be float, double or long double.
In C++, it is implemented with function overloads for each floating-point type, each returning a bool value.
How can I fix this?
Although you can mitigate this problem by not saying using namespace std; everywhere, you can avoid it by being explicit about using std::isnan:
#include <cmath>
#include <iostream>
int main()
{
double x = ....;
std::cout << std::boolalpha;
std::cout << std::isnan(x) << std::endl;
}
In C++11 there should not be ambiguity between the C and C++ isnan function. It works as expected, even with using namespace std.
Please check that you are not doing both #include <math.h> and #include <cmath>. Only include cmath.
Alternatively, perhaps you somewhere have in your project a user-defined isnan(double) function, or some header includes "math.h".
Also please note, that if one wants to write generic code, it is incorrect to use the 'std::' prefix on the math functions as it breaks the argument dependent lookup (ADL). (Because the C++ standard does not allow injecting functions in the std:: namespace)
The correct use for isnan in generic code is using std::isnan; then use just isnan on the variables. Otherwise your code with user defined floating point types such as for arbitrary precision, automatic differentiation and such wont work. The root of this inconsistency is that the built in types such as double do not reside in the namespace std but the functions that operate on them do.
I was playing with ptrdiff_t and reading the C++11 standard when I came across this "issue". First, the facts:
The type ptrdiff_t (just an example) is pulled from the Standard C library header <stddef.h> into <cstddef> (§18.2/2). Section 17.6.1.2 tells us that declarations pulled from the C standard library will be within the std namespace:
In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is
unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
As it also says, the declarations may have been declared in global namespace first and then injected into std. So it would make sense, for my implementation, that the following compiles just fine:
#include <cstddef>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
My implementation (gcc 4.6.3) must have declared ptrdiff_t in the global namespace and then injected it into std. However, if I compile the following code, I get an error (notice the <iostream> include):
#include <iostream>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
main.cpp: In function ‘int main(int, const char**)’:
main.cpp:6:3: error: ‘ptrdiff_t’ was not declared in this scope
main.cpp:6:3: note: suggested alternatives:
/usr/include/c++/4.6/i686-linux-gnu/./bits/c++config.h:156:28: note: ‘std::ptrdiff_t’
So, since std::ptrdiff_t is available, <iostream> must be including <cstddef> in some way (although it's not required to). But why is the global version not also available as it
was before? Can I not expect this injection to be consistent even when it's actually the same header? This seems like odd behaviour. Whether the injection occurs may be unspecified, but it should at least be either one way or the other, not both, right?
Do not rely on one header including another, if you want something declared/defined in a specific header then you must include it.
For the example you gave, with g++ there are actually two definitions of ptrdiff_t (and size_t for that matter). The first, in namespace std, that comes from <bits/c++config.h>. And the one in the global namespace from <stddef.h> (and so <cstddef>).
The problem is that you did not using the correct header. You should do
#include <cstddef>
instead. However you use
#include<iostream>
And that has a definition of "std::ptrdiff_t" in it indirectly. However, the global "::ptrdiff_t" is not defined in "iostream" and "iostream" did not include "cstddef" as you thought. Instead, "iostream" does include "bits/c++config.h". The actual "std::ptrdiff_t" is defined in that file.
If you look at the content of the file "cstddef" you will find that is is only two "useful" lines there
BTW, the above discussion is for GCC 4.6 and GCC 4.7. For GCC 4.4, "iostream" indrectly include "cstddef" therefore ptrdiff_t will be available in both namespaces (std and global).
#include
#include
The latter line brings in the global "::ptrdiff_t" and the former defines the std namespace one.