C++ std::transform() 和 toupper(),没有匹配的函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7131858/
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
std::transform() and toupper(), no matching function
提问by Stack Overeem
I tried the code from this question C++ std::transform() and toupper() ..why does this fail?
我尝试了这个问题C++ std::transform() 和 toupper() 中的代码..为什么会失败?
#include <iostream>
#include <algorithm>
int main() {
std::string s="hello";
std::string out;
std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper);
std::cout << "hello in upper case: " << out << std::endl;
}
Theoretically it should've worked as it's one of the examples in Josuttis' book, but it doesn't compile http://ideone.com/aYnfv.
从理论上讲,它应该可以工作,因为它是 Josuttis 书中的示例之一,但它无法编译http://ideone.com/aYnfv。
Why did GCC complain:
为什么海湾合作委员会抱怨:
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> > >,
std::back_insert_iterator<std::basic_string
<char, std::char_traits<char>, std::allocator<char> > >,
<unresolved overloaded function type>)'
Am I missing something here? Is it GCC related problem?
我在这里错过了什么吗?是 GCC 相关的问题吗?
回答by Nawaz
Just use ::toupper
instead of std::toupper
. That is, toupper
defined in the global namespace, instead of the one defined in std
namespace.
只需使用::toupper
代替std::toupper
. 也就是说,toupper
定义在全局命名空间中,而不是在std
命名空间中定义的。
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
Its working : http://ideone.com/XURh7
它的工作原理:http: //ideone.com/XURh7
Reason why your code is not working : there is another overloaded function toupper
in the namespace std
which is causing problem when resolving the name, because compiler is unable to decide which overload you're referring to, when you simply pass std::toupper
. That is why the compiler is saying unresolved overloaded function type
in the error message, which indicates the presence of overload(s).
您的代码不工作的原因:toupper
命名空间中有另一个重载函数在std
解析名称时导致问题,因为编译器无法确定您指的是哪个重载,当您简单地传递std::toupper
. 这就是编译器unresolved overloaded function type
在错误消息中说的原因,这表明存在重载。
So to help the compiler in resolving to the correct overload, you've to cast std::toupper
as
因此,为了帮助编译器解析正确的重载,您必须将其转换std::toupper
为
(int (*)(int))std::toupper
That is, the following would work:
也就是说,以下内容将起作用:
//see the last argument, how it is casted to appropriate type
std::transform(s.begin(), s.end(), std::back_inserter(out),(int (*)(int))std::toupper);
Check it out yourself: http://ideone.com/8A6iV
自己检查一下:http: //ideone.com/8A6iV
回答by Lightness Races in Orbit
Problem
问题
std::transform(
s.begin(),
s.end(),
std::back_inserter(out),
std::toupper
);
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> > >, std::back_insert_iterator<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> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)
”的匹配函数
This is a misleading error; the interesting part is not that there's "no matching function" for the call, but whythere's no matching function.
这是一个误导性的错误;有趣的部分不是调用“没有匹配函数”,而是为什么没有匹配函数。
The whyis that you're passing a function reference of an "<unresolved overloaded function type>
" as an argument, and GCC prefers to error on the call rather than on this overload resolution failure.
的原因是,你传递的“函数引用<unresolved overloaded function type>
”作为参数,并GCC喜欢上的错误电话,而不是在这个重载解析失败。
Explanation
解释
First, you should consider how the C library is inherited in C++. <ctype.h>
has a function int toupper(int)
.
首先,您应该考虑如何在 C++ 中继承 C 库。<ctype.h>
有一个功能int toupper(int)
。
C++ inherits this:
C++ 继承了这一点:
[n3290: 21.7/1]:
Tables 74, 75, 76, 77, 78, and 79 describe headers<cctype>
,<cwctype>
,<cstring>
,<cwchar>
,<cstdlib>
(character conversions), and<cuchar>
, respectively.
[n3290: 21.7/2]:
The contents of these headers shall be the same as the Standard C Library headers<ctype.h>
,<wctype.h>
,<string.h>
,<wchar.h>
, and<stdlib.h>
and the C Unicode TR header<uchar.h>
, respectively [..]
[n3290: 17.6.1.2/6]:
Names that are defined as functions in C shall be defined as functions in the C++ standard library.
[n3290: 21.7/1]:
表 74、75、76、77、78 和 79 分别描述了标题<cctype>
、<cwctype>
、<cstring>
、<cwchar>
、<cstdlib>
(字符转换)和<cuchar>
。
[n3290: 21.7/2]:
这些头文件的内容应分别与标准 C 库头文件<ctype.h>
、<wctype.h>
、<string.h>
、<wchar.h>
、 和<stdlib.h>
C Unicode TR 头文件<uchar.h>
相同 [..]
[n3290: 17.6.1.2/6]:
在 C 中定义为函数的名称应在 C++ 标准库中定义为函数。
But using <ctype.h>
is deprecated:
但<ctype.h>
不推荐使用:
[n3290: C.3.1/1]:
For compatibility with the Standard C library, the C++ standard library provides the 18 C headers (D.5), but their use is deprecated in C++.
[n3290: C.3.1/1]:
为了与标准 C 库兼容,C++ 标准库提供了 18 个 C 头文件 (D.5),但在 C++ 中不推荐使用它们。
And the way to access the C toupper
is through the C++ backwards-compatibility header <cctype>
. For such headers, the contents are either moved or copied(depending on your implementation) into the std
namespace:
访问 C 的方式toupper
是通过 C++ 向后兼容头文件<cctype>
。对于此类标头,将内容移动或复制(取决于您的实现)到std
命名空间中:
[n3290: 17.6.1.2/4]:
[..] 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).
[n3290: 17.6.1.2/4]:
[..] 然而,在 C++ 标准库中,声明(除了在 C 中定义为宏的名称)在命名空间 std 的命名空间范围 (3.3.6) 内。未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式 using 声明(7.3.3)注入命名空间 std。
But the C++ library also introduces a new, locale-specific function template in header <locale>
, that's alsocalled toupper
(of course, in namespace std
):
但是 C++ 库还在 header 中引入了一个新的、特定于语言环境的函数模板<locale>
,它也被称为toupper
(当然,在 namespace 中std
):
[n3290: 22.2]:
[..]template <class charT> charT toupper(charT c, const locale& loc);
[..]
[n3290: 22.2]:
[..]template <class charT> charT toupper(charT c, const locale& loc);
[..]
So, when you use std::toupper
, there are twooverloads to choose from. Since you didn't tell GCC which function you wish to use, the overload cannot be resolved and your call to std::transform
cannot be completed.
因此,当您使用 时std::toupper
,有两种重载可供选择。由于您没有告诉 GCC 您希望使用哪个函数,因此无法解决重载并且无法std::transform
完成您的调用。
Disparity
差距
Now, the OP of that original question did not run into this problem. He likely did not have the locale version of std::toupper
in scope, but then again you didn't #include <locale>
either!
现在,那个原始问题的 OP 没有遇到这个问题。他可能没有std::toupper
范围内的语言环境版本,但是您也没有#include <locale>
!
However:
然而:
[n3290: 17.6.5.2]:
A C++ header may include other C++ headers.
[n3290: 17.6.5.2]:
C++ 头文件可能包含其他 C++ 头文件。
So it just so happensthat either your <iostream>
or your <algorithm>
, or headers that those headers include, or headers that thoseheaders include (etc), lead to the inclusion of <locale>
on your implementation.
因此,碰巧您<iostream>
或您的<algorithm>
, 或这些标头包含的标头,或这些标头包含的标头(等)导致包含<locale>
在您的实现中。
Solution
解决方案
There are two workarounds to this.
对此有两种解决方法。
You may provide a conversion clause to coerce the function pointer into referring to the overload that you wish to use:
std::transform( s.begin(), s.end(), std::back_inserter(out), (int (*)(int))std::toupper // specific overload requested );
You may remove the locale version from the overload set by explicitly using the global
toupper
:std::transform( s.begin(), s.end(), std::back_inserter(out), ::toupper // global scope );
However, recall that whether or not this function in
<cctype>
is available is unspecified ([17.6.1.2/4]
), and using<ctype.h>
is deprecated ([C.3.1/1]
).Thus, this is not the option that I would recommend.
您可以提供一个转换子句来强制函数指针引用您希望使用的重载:
std::transform( s.begin(), s.end(), std::back_inserter(out), (int (*)(int))std::toupper // specific overload requested );
您可以通过显式使用 global 从重载集中删除语言环境版本
toupper
:std::transform( s.begin(), s.end(), std::back_inserter(out), ::toupper // global scope );
但是,请记住此函数
<cctype>
是否可用是未指定的 ([17.6.1.2/4]
),并且 using<ctype.h>
已弃用 ([C.3.1/1]
)。因此,这不是我推荐的选项。
(Note:I despise writing angle brackets as if they were part of header names — they are part of #include
syntax, not header names — but I've done it here for consistency with the FDIS quotes; and, to be honest, it isclearer...)
(注:我鄙视写尖括号,如果他们头名的一部分-他们的部分#include
语法,而不是标题名称-但是我在这里做了它与FDIS报价一致性;而且,说实话,这是更清晰...)
回答by John Chang
std::transform(s.begin(), s.end(), s.begin(),
std::bind(&std::toupper<char>, std::placeholders::_1, std::locale()));
If you use vc toolchain,please include locale
如果您使用 vc 工具链,请包括语言环境