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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:29:56  来源:igfitidea点击:

std::transform() and toupper(), no matching function

c++algorithmstl

提问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 ::toupperinstead of std::toupper. That is, toupperdefined in the global namespace, instead of the one defined in stdnamespace.

只需使用::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 toupperin the namespace stdwhich 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 typein 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::toupperas

因此,为了帮助编译器解析正确的重载,您必须将其转换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 toupperis through the C++ backwards-compatibility header <cctype>. For such headers, the contents are either moved or copied(depending on your implementation) into the stdnamespace:

访问 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::transformcannot 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::toupperin 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.

对此有两种解决方法。

  1. 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
    );
    
  2. 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.

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

    std::transform(
       s.begin(),
       s.end(),
       std::back_inserter(out),
       (int (*)(int))std::toupper  // specific overload requested
    );
    
  2. 您可以通过显式使用 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 #includesyntax, 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 工具链,请包括语言环境