C++ 为什么“transform(s.begin(),s.end(),s.begin(),tolower)”不能成功编译?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5539249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't "transform(s.begin(),s.end(),s.begin(),tolower)" be complied successfully?
提问by liu
Given the code:
鉴于代码:
#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s("ABCDEFGHIJKL");
transform(s.begin(),s.end(),s.begin(),tolower);
cout<<s<<endl;
}
I get 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>)
没有匹配的函数调用
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 does "unresolved overloaded function type"mean?
什么是“未解决重载函数类型”是什么意思?
If I replace the tolower
with a function I wrote, it no longer errors.
如果我用tolower
我写的函数替换它,它就不再出错。
采纳答案by davka
Try using ::tolower
. This fixed the problem for me.
尝试使用::tolower
. 这为我解决了问题。
回答by David Rodríguez - dribeas
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>
.
该问题很可能与 的多个重载有关tolower
,并且编译器无法为您选择一个。您可以尝试限定它以选择它的特定版本,或者您可能需要提供一个函数指针来消除歧义。该tolower
函数可以出现在<locale>
头文件中(多个不同的重载),也可以出现在<cctype>
.
Try:
尝试:
int (*tl)(int) = tolower; // Select that particular overload
transform(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 );
回答by Jonathan Mee
Let's look at a list of options starting with the worst and moving to the best. We'll list them here and discuss them below:
让我们看一下从最坏开始到最好的选项列表。我们将在此处列出它们并在下面讨论它们:
transform(cbegin(s), cend(s), begin(s), ::tolower)
transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
transform(cbegin(s), cend(s), begin(s), ::tolower)
transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
The code in your question, transform(s.begin(), s.end(), s.begin(), tolower)
will produce an error like:
您问题中的代码transform(s.begin(), s.end(), s.begin(), tolower)
将产生如下错误:
No matching function for call to
transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)
没有匹配的函数调用
transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)
The reason that you were getting an "unresolved overloaded function type" is there are 2 tolower
s in the std
namespace:
那你得到一个“未解决重载函数型”的原因是有2个tolower
S IN的std
命名空间:
- The
locale
library definestemplate <typename T> T tolower(T, const locale&)
- The
cctype
library definesint tolower(int)
- 该
locale
库定义template <typename T> T tolower(T, const locale&)
- 该
cctype
库定义int tolower(int)
1is the solution offered by davka. It addresses your error by leveraging the fact that locale
's tolower
is not defined in the global namespace.
1是davka 提供的解决方案。它通过利用locale
'stolower
未在全局命名空间中定义的事实来解决您的错误。
Depending upon your situation locale
's tolower
may merit consideration. You can find a comparison of the tolower
s here: Which tolower in C++?
根据您的情况locale
,tolower
可能值得考虑。您可以在tolower
此处找到s的比较:C++ 中的哪个 tolower?
Unfortunately 1depends upon cctype
's tolower
being defined in the global namespace. Let's look at why that may not be the case:
不幸的是1取决于cctype
'stolower
在全局命名空间中的定义。让我们看看为什么情况并非如此:
You are rightly using #include <cctype>
, as doing #include <ctype.h>
has been deprecated in C++: http://en.cppreference.com/w/cpp/header
您正在正确使用#include <cctype>
,因为#include <ctype.h>
在 C++ 中已弃用:http: //en.cppreference.com/w/cpp/header
But the C++ standard states in D.3[depr.c.headers]2 of the declarations in the headers:
但是 C++ 标准在头文件中的声明的 D.3[depr.c.headers]2 中声明:
It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace
std
and are then injected into the global namespace scope by explicit using-declarations (7.3.3)
未指定这些名称是否首先在命名空间的命名空间范围 (3.3.6) 中声明或定义
std
,然后通过显式 using 声明 (7.3.3) 注入到全局命名空间范围中
So the only way that we can guarantee our code is implementation independent is to use a tolower
from namespace std
. 2is the solution offered by David Rodríguez - dribeas. It leverages the fact that static_cast
can:
因此,我们可以保证我们的代码与实现无关的唯一方法是使用tolower
from namespace std
。2是David Rodríguez-dribeas 提供的解决方案。它利用了以下事实static_cast
:
Be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
用于通过执行到特定类型的函数到指针的转换来消除函数重载的歧义
Before we move on, let me comment that if you find int (*)(int)
to be a bit confusing you can read more on function pointer syntax here.
在我们继续之前,让我评论一下,如果你觉得int (*)(int)
有点困惑,你可以在这里阅读更多关于函数指针语法的信息。
Sadly there is one other issuewith tolower
's input argument, if it:
可悲的是,的输入参数还有另一个问题tolower
,如果它:
Is not representable as unsigned char and does not equal EOF, the behavior is undefined
不可表示为无符号字符且不等于 EOF,行为未定义
You are using a string
which uses elements of type: char
. The standard states of char
specifically 7.1.6.2[dcl.type.simple]3:
您正在使用 a string
,它使用类型为: 的元素char
。char
具体7.1.6.2[dcl.type.simple]3的标准状态:
It is implementation-defined whether objects of
char
type are represented as signed or unsigned quantities. Thesigned
specifier forceschar
objects to be signed
char
类型的对象是否表示为有符号或无符号数量是实现定义的。该signed
说明符的力量char
要签名的对象
So if the implementation defined a char
to mean a signed char
then both 1and 2would result in Undefined Behavior for all characters corresponding to negative numbers. (If an ASCII character encoding is being used the characters corresponding to negative numbers are Extended ASCII.)
因此,如果实现定义了 achar
表示 a,signed char
那么1和2都会导致与负数对应的所有字符的未定义行为。(如果使用 ASCII 字符编码,则对应于负数的字符是Extended ASCII。)
The Undefined Behavior can be avoided by converting the input to an unsigned char
before passing it to tolower
. 3accomplishes that using a lambda that accepts an unsigned char
by value, then passes it to tolower
implicitly converting to int
.
通过在将输入unsigned char
传递给 之前将输入转换为 an 可以避免未定义行为tolower
。3使用一个接受unsigned char
by 值的 lambda 实现了这一点,然后将其传递给tolower
隐式转换为int
.
To guarantee Defined Behavior on all compliant implementations, independent of character encoding, you'll need to use transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
or something similar.
为了保证所有兼容实现的定义行为,独立于字符编码,您需要使用transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
或类似的东西。
回答by Matthieu M.
David already identified the issue, namely a conflict between:
David 已经确定了这个问题,即以下之间的冲突:
<cctype>
'sint tolower(int c)
<locale>
'stemplate <typename charT> charT tolower(charT c, locale const& loc)
<cctype>
的int tolower(int c)
<locale>
的template <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.
使用第一个要容易得多,但是一旦处理除符号字符中的低位 ascii (0-127) 以外的任何其他内容,就会出现未定义的行为(不幸的是)。顺便说一下,我建议定义char
为无符号。
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...
模板版本会很好,但是您必须使用bind
来提供第二个参数,而且它肯定很难看...
So, may I introduce the Boost String Algorithm library ?
那么,我可以介绍一下Boost String Algorithm 库吗?
And more importantly: boost::to_lower
:)
更重要的是boost::to_lower
:)
boost::to_lower(s);
Expressiveness is desirable.
表现力是可取的。
回答by Mike DeSimone
Browsing my <ctype>
header from gcc 4.2.1, I see this:
<ctype>
从 gcc 4.2.1浏览我的标题,我看到了这个:
// -*- 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 the std
(from <cctype>
) and root (from <ctype.h>
) namespaces. I'm not sure what the #pragma
does.
所以它看起来tolower
同时存在于std
(from <cctype>
) 和 root (from <ctype.h>
) 命名空间中。我不确定它有什么#pragma
作用。