5

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?
Community
  • 1
  • 1
Martin Wang
  • 957
  • 14
  • 18
  • [Looks relevant](http://en.wikipedia.org/wiki/Argument-dependent_name_lookup#Criticism). – chris Jul 16 '12 at 06:28
  • 1
    Same problem is here with detail answer : [unresolved overloaded function type c++](http://stackoverflow.com/questions/7531866/unresolved-overloaded-function-type-c) – Nawaz Jul 16 '12 at 06:58

2 Answers2

5

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.

Gui13
  • 12,993
  • 17
  • 57
  • 104
  • That's to say: `#include ` means global namespace, while `#include ` in `std` namespace? – Martin Wang Jul 16 '12 at 06:26
  • Kind of, yes. But `std::tolower` is in ``, not `` :-) – Gui13 Jul 16 '12 at 06:29
  • 3
    And as usual, that "reference" is wrong. It's in `` according to http://en.cppreference.com/w/cpp/string/byte/tolower and I just checked myself with both of my files. – chris Jul 16 '12 at 06:31
  • Ah, nice! `` overloads the function with an additional *locale* argument. You're absolutely right. – Gui13 Jul 16 '12 at 06:32
  • @Gui13, Ah, that explains it. I didn't find any mention of that overload in my `` and if you navigate to the other overload, it's put in the right section. Apart from that confusion, though, it *is* known to have errors. – chris Jul 16 '12 at 06:37
  • Then why C++ cann't resolve tolower when `using namespace std`? Just because C++ template can't distinguish two overloaded function? – Martin Wang Jul 16 '12 at 06:49
  • @Martin See the related answer here: http://stackoverflow.com/questions/7531866/unresolved-overloaded-function-type-c (Nawaz proposed it in the comments of your question) – Gui13 Jul 16 '12 at 11:10
5

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329