c++ - 为什么 "transform(s.begin(),s.end(),s.begin(),tolower)"编译不成功?

标签 c++ compiler-errors lowercase toupper tolower

给定代码:

#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
     string s("ABCDEFGHIJKL");
     transform(s.begin(),s.end(),s.begin(),tolower);
     cout<<s<<endl;
}

我得到错误:

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> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)

“未解析的重载函数类型”是什么意思?

如果我替换 tolower使用我编写的函数,它不再出错。

最佳答案

让我们看一个选项列表,从最差的开始到最好的。我们将在此处列出它们并在下面讨论它们:

  1. transform(cbegin(s), cend(s), begin(s), ::tolower)
  2. transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
  3. transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })

您问题中的代码 transform(s.begin(), s.end(), s.begin(), tolower)会产生如下错误:

No matching function for call to transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)

您得到“未解析的重载函数类型”的原因是有 2 tolowerstd命名空间:

  1. locale库定义 template <typename T> T tolower(T, const locale&)
  2. cctype库定义 int tolower(int)

1solution offered by davka .它利用 locale 的事实来解决您的错误。的tolower未在全局命名空间中定义。

根据您的情况localetolower可能值得考虑。您可以找到 tolower 的比较在这里:Which tolower in C++?


不幸的是 1 取决于 cctypetolower在全局命名空间中定义。让我们看看为什么不是这样:

您正确地使用了#include <cctype> , 就像 #include <ctype.h>在 C++ 中已弃用:http://en.cppreference.com/w/cpp/header

但 C++ 标准在 D.3[depr.c.headers]2 中声明了 header 中的声明:

It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3)

因此,我们可以保证我们的代码独立于实现的唯一方法是使用 tolower来自 namespace std . 2solution offered by David Rodríguez - dribeas .它利用了 static_cast 可以:

Be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type

在我们继续之前,让我评论一下,如果您找到 int (*)(int)有点困惑你可以阅读更多关于函数指针语法here .


很遗憾有 one other issuetolower的输入参数,如果是:

Is not representable as unsigned char and does not equal EOF, the behavior is undefined

您正在使用 string它使用以下类型的元素:char . char 的标准状态特别是 7.1.6.2[dcl.type.simple]3:

It is implementation-defined whether objects of char type are represented as signed or unsigned quantities. The signed specifier forces char objects to be signed

所以如果实现定义了 char表示 signed char那么 12 都会导致与负数对应的所有字符的未定义行为。 (如果使用 ASCII 字符编码,则负数对应的字符为 Extended ASCII。)

可以通过将输入转换为 unsigned char 来避免未定义行为在传递给 tolower 之前. 3 使用接受 unsigned char 的 lambda 来完成此操作。按值传递给 tolower隐式转换为 int .

为了保证所有兼容实现的定义行为,独立于字符编码,您需要使用 transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })或类似的东西。

关于c++ - 为什么 "transform(s.begin(),s.end(),s.begin(),tolower)"编译不成功?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5539249/

相关文章:

c++ - 如何在 C++ 中创建类对象的 vector ?

java - "error: ' .class' expected"是什么意思,我该如何解决

c++ - 代码 :Blocks Mingw Compiler Error: Variable-Sized Object May Not Be Initialized

string - 将 unicode 字符转换为小写的标准算法是什么?

c++ - Visual Studio 2010 中未解析的外部符号

c++ - 为什么我的本地 dll 在设置 _NT_SYMBOL_PATH 后永远加载?

java - 内部错误;无法实例化 <class>.<init>

Python 小写​​列表理解测试失败时似乎是正确的?

java - Hive:将小写字母应用于数组

c++ - C++ 中类定义的顺序