std :: transform()和toupper(),没有匹配的函数

时间:2011-08-20 12:53:56

标签: c++ algorithm stl

我尝试了这个问题的代码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相关的问题吗?

3 个答案:

答案 0 :(得分:68)

只需使用::toupper代替std::toupper。也就是说,toupper在全局命名空间中定义,而不是在std命名空间中定义的那个。

std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);

它的工作:http://ideone.com/XURh7

您的代码无效的原因:名称空间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);

亲自查看:http://ideone.com/8A6iV

答案 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>包含在您的实现中。


解决方案

这有两种解决方法。

  1. 您可以提供一个转换子句来强制函数指针引用您想要使用的重载:

    std::transform(
       s.begin(),
       s.end(),
       std::back_inserter(out),
       (int (*)(int))std::toupper  // specific overload requested
    );
    
  2. 您可以通过显式使用全局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])。

    因此,这不是我推荐的选项。


  3. 注意:我鄙视写尖括号,好像它们是标题名称的一部分 - 它们是#include语法的一部分,而不是标题名称 - 但我已经完成了它是为了与FDIS报价保持一致;而且,说实话,它 更清楚......)

答案 2 :(得分:0)

std::transform(s.begin(), s.end(), s.begin(), 
std::bind(&std::toupper<char>, std::placeholders::_1, std::locale()));

如果您使用vc工具链,请添加语言环境