我尝试了这个问题的代码C++ std::transform() and toupper() ..why does this fail?
#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。
为什么海湾合作委员会抱怨:
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相关的问题吗?
答案 0 :(得分:68)
只需使用::toupper
代替std::toupper
。也就是说,toupper
在全局命名空间中定义,而不是在std
命名空间中定义的那个。
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
您的代码无效的原因:名称空间toupper
中有另一个重载函数std
,这在解析名称时会导致问题,因为编译器无法确定您引用的是哪个重载当你只是通过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);
答案 1 :(得分:42)
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>)
”
这是一个误导性错误;有趣的部分并不是呼叫的“没有匹配功能”,而是为什么没有匹配的功能。
为什么是您传递“<unresolved overloaded function type>
”的函数引用作为参数,而GCC更喜欢调用错误而不是此重载解析失败。
首先,您应该考虑如何在C ++中继承C库。 <ctype.h>
有一个函数int toupper(int)
。
C ++继承了这个:
[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中定义为宏的名称除外)在其中 命名空间std的命名空间范围(3.3.6)。 未指明 是否首先在全局命名空间中声明这些名称 范围然后通过显式注入到命名空间std中 使用声明(7.3.3)。
但是C ++库还在头文件<locale>
中引入了一个新的,特定于语言环境的函数模板,其也称为toupper
(当然,在名称空间std
中}):
[n3290: 22.2]:
[..]template <class charT> charT toupper(charT c, const locale& loc);
[..]
因此,当您使用std::toupper
时,有两个重载可供选择。由于您没有告诉GCC您希望使用哪种功能,因此无法解决超载问题,并且无法完成对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报价保持一致;而且,说实话,它 更清楚......)
答案 2 :(得分:0)
std::transform(s.begin(), s.end(), s.begin(),
std::bind(&std::toupper<char>, std::placeholders::_1, std::locale()));
如果您使用vc工具链,请添加语言环境