std :: transform()和toupper(),没有匹配的函数
我试过这个问题的代码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; }
从理论上讲,它应该是Josuttis书中的例子之一,但它不能编译http://ideone.com/aYnfv 。
为什么GCC抱怨:
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>)'
我在这里错过了什么? 是GCC相关的问题?
只需使用::toupper
而不是std::toupper
。 也就是说,在全局命名空间中定义toupper
,而不是在std
命名空间中定义的。
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
其工作: http : //ideone.com/XURh7
你的代码不工作的原因:在名字空间std
有另外一个重载的函数toupper
,当parsing这个名字的时候会造成问题,因为当你简单地通过std::toupper
时,编译器无法决定你指的是哪个超载。 这就是为什么编译器在错误信息中说明了unresolved overloaded function type
,这表明存在过载。
所以为了帮助编译器解决正确的重载问题,你必须将std::toupper
作为
(int (*)(int))std::toupper
也就是说,以下是可行的:
//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);
请自行检查: http : //ideone.com/8A6iV
问题
std::transform( s.begin(), s.end(), std::back_inserter(out), std::toupper );
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>)
'
这是一个误导性的错误; 有趣的部分并不是说调用没有“匹配的function”,而是为什么没有匹配的function。
为什么你传递一个“ <unresolved overloaded function type>
”的函数引用作为参数,而GCC更喜欢错误的调用,而不是这个重载parsing失败。
说明
首先,你应该考虑如何在C ++中inheritanceC库。 <ctype.h>
有一个函数int toupper(int)
。
C ++inheritance了这个:
[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 ++标准库中的函数。
但是使用<ctype.h>
已经被弃用:
[n3290: C.3.1/1]:
为了与标准C库兼容,C ++标准库提供了18 C头文件(D.5),但在C ++中不推荐使用它们。
而访问C toupper
是通过C ++向后兼容的头文件<cctype>
。 对于这样的头文件,内容被移动或复制 (取决于你的实现)到std
名称空间中:
[n3290: 17.6.1.2/4]:
[..]然而,在C ++标准库中,声明(在C中定义为macros的名称除外)位于名称空间std的名称空间范围(3.3.6)内。 没有指定这些名称是否在全局命名空间范围内首先声明,然后通过显式使用声明 (7.3.3) 注入命名空间std 。
但是C ++库还在头文件<locale>
引入了一个新的特定于语言环境的函数模板,这个模板也被称为toupper
(当然,在命名空间std
):
[n3290: 22.2]:
[..]template <class charT> charT toupper(charT c, const locale& loc);
[..]
所以,当你使用std::toupper
,有两个重载可供select。 既然你没有告诉GCC你希望使用哪个函数,那么重载就不能被parsing,你对std::transform
调用就不能完成了。
差距
现在,这个原始问题的OP没有遇到这个问题。 他可能没有范围内的std::toupper
的语言环境版本,但是又没有#include <locale>
!
然而:
[n3290: 17.6.5.2]:
C ++头文件可能包含其他C ++头文件。
所以只要你的<iostream>
或者你的<algorithm>
,这些头文件包含的头文件,或者这些头文件包含的头文件等等,都会导致在你的实现中包含<locale>
。
解
有两个解决方法。
-
您可以提供一个转换子句来强制函数指针指向您希望使用的重载:
std::transform( s.begin(), s.end(), std::back_inserter(out), (int (*)(int))std::toupper // specific overload requested );
-
您可以通过明确使用全局
toupper
来从重载设置中删除区域设置版本:std::transform( s.begin(), s.end(), std::back_inserter(out), ::toupper // global scope );
但是,请记住,
<cctype>
此函数是否可用是未指定的([17.6.1.2/4]
),并且已使用<ctype.h>
([C.3.1/1]
)。因此,这不是我会推荐的选项。
( 注意:我鄙视书写尖括号,就好像它们是标题名称的一部分 – 它们是#include
语法的一部分,而不是标题名称 – 但是为了与FDIS引用的一致性,我在这里做了它;而且,老实说,更清楚…)