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

来源:互联网 发布:交通组织优化有哪些 编辑:程序博客网 时间:2024/06/07 13:00

From: http://stackoverflow.com/questions/5539249/why-transforms-begin-s-end-s-begin-tolower-cant-be-complied-successfu

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

up vote7 down vote favorite
3
#include<iostream>#include<cctype>#include<string>#include<algorithm>using namespace std;main(){     string s("ABCDEFGHIJKL");     transform(s.begin(),s.end(),s.begin(),tolower);     cout<<s<<endl;}

the error:

no matching function for call to 'transform(__gnu_cxx::__normal_iterator<char*,   std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)'`

What the "unresolved overloaded function type" means?

if I replace the tolower of a function written by myself ,it can work.

share|improve this question
 
2 
The return type ofmain is int, and return types in C++ have to be explicit. Some compilers will allow the code as posted, but it is non-standard, and it might break with the new compiler version or in other compilers. – David Rodríguez - dribeas Apr 4 '11 at 15:21

4 Answers

activeoldest votes
up vote8 down vote accepted

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

share|improve this answer
 
1 
It's right. What's difference betweentolower and ::tolower? – liu Apr 4 '11 at 14:06
 
@liu: it's as @David wrote - the "::" selects thetolower from the global namespace – davka Apr 4 '11 at 14:16
up vote13 down vote

The problem most probably relates with multiple overloads of tolower and the compiler is unable to select one for you. You can try qualifying it to select an specific version of it, or you might need to provide a function pointer cast to disambiguate. The tolower function can be present (multiple different overloads) in the<locale> header, as well as in <cctype>.

Try:

int (*tl)(int) = tolower; // Select that particular overloadtransform(s.begin(),s.end(),s.begin(),tl );

That can be done in a single line with a cast, but it is probably harder to read:

transform(s.begin(),s.end(),s.begin(),(int (*)(int))tolower );
share|improve this answer
 
3 
But don't forget that using this version oftolower on a string like the above is undefined behavior if any of the char values are negative (which they can be on most modern systems, e.g. if any accented characters are present). – James Kanze Apr 4 '11 at 13:49
1 
@James Kanze: good point, I decided for that overload from reading the original post (where cctype is explicitly included, while locale is not). Also, the functions in locale take more than a single argument, and that means that the code would add unrelated complexity with abind or bind2nd to provide the default locale... – David Rodríguez - dribeas Apr 4 '11 at 13:58
 
Thank you.I understand the problem. And using ::tolower can fix the problem – liu Apr 4 '11 at 14:11
1 
@liu: Note that using::tolower will work in different compilers, but it is not standard. Basically most compilers, when you includecctype the compiler is required to provide int std::tolower(int), but it is not required to addint ::tolower(int), different compilerswill provide both functions with the same implementation (one of them will forward to the other) but that is not required and might change with the next compiler release (or if you change the compiler) – David Rodríguez - dribeas Apr 4 '11 at 15:20
1 
@liu Using::tolower doesn't fix the problem. Calling::tolower with achar argument is undefined behavior. You need to wrap it in a functional object which converts thechar to unsigned char. Or buy into all of the complexity that David Rodríguez mentions with regards to the versions in<locale>. –  James Kanze Apr 4 '11 at 16:40
up vote2 down vote

Browsing my <ctype> header from gcc 4.2.1, I see this:

// -*- C++ -*- forwarding header.// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005// Free Software Foundation, Inc.

...

#ifndef _GLIBCXX_CCTYPE#define _GLIBCXX_CCTYPE 1#pragma GCC system_header#include <bits/c++config.h>#include <ctype.h>// Get rid of those macros defined in <ctype.h> in lieu of real functions.#undef isalnum#undef isalpha

...

#undef tolower#undef toupper_GLIBCXX_BEGIN_NAMESPACE(std)  using ::isalnum;  using ::isalpha;

...

  using ::tolower;  using ::toupper;_GLIBCXX_END_NAMESPACE#endif

So it looks like tolower exists in both thestd (from <cctype>) and root (from <ctype.h>) namespaces. I'm not sure what the#pragma does.

share|improve this answer
 
1 
the pragma signals to gcc that this file is a system header. This should typically affect diagnosis, since it's considered bad style for a compiler to emit warnings for headers that it was bundled with and should not be altered. –  Matthieu M. Apr 4 '11 at 19:12
up vote2 down vote

David already identified the issue, namely a conflict between:

  • <cctype>'sint tolower(int c)
  • <locale>'stemplate <typename charT> charT tolower(charT c, locale const& loc)

Using the first is much easier, but is undefined behavior (unfortunately) as soon as you deal with anything else than lower-ascii (0-127) in signed chars.By the way, I do recommend defining char as unsigned.

The template version would be nice, but you would have to use bind to provide the second parameter, and it's bound to be ugly...

So, may I introduce the Boost String Algorithm library ?

And more importantly: boost::to_lower :)

boost::to_lower(s);

Expressiveness is desirable.

share|improve this answer
 
 
1) can you please explain what do you mean byI do recommend defining char as unsigned? 2) does boost::to_lower assumes some character set, e.g. latin-1? – davka Apr 5 '11 at 15:27
 
@davka: 1) theC++ Standard does not precise whether achar is signed or unsigned. You can qualify it if you want to be sure. However a number of functions (likeint tolower(int)) have undefined behavior if invoked with a negativechar... Look it up on your compiler, there might be a switch or a sane default. 2)boost::to_lower is based on the C++ tolower function, and thus depends on thestd::locale and the ctype facet it has been imbued with. Note that these facets cannot handle multi-characters encoding anyway... – Matthieu M. Apr 5 '11 at 15:37
 
thanks, I still don't get #1. I know aboutchar being implementation-dependent. Are you suggesting typedef unsigned char char? is it legal? – davka Apr 5 '11 at 15:43
1 
@davka: No, it's not legal. Compilers usually have switches to let you decide, for examplegcc has -fsigned-char and -funsigned-char. – Matthieu M. Apr 5 '11 at 17:00
 
that's interesting, thanks. So, if I use-funsigned-char I should use signed char if I want -128..127, correct? Does it work well with 3rd party libraries that are not compiled with this flag? – davka Apr 5 '11 at 17:09

0 0
原创粉丝点击