std::tolower and Visual Studio 2013
std::tolower and Visual Studio 2013
我试着了解如何使用std::tolower
...
#include <iostream>
#include <string>
#include <algorithm>
#include <locale>
int main()
{
std::string test = "Hello World";
std::locale loc;
for (auto &c : test)
{
c = std::tolower(c, loc);
}
std::transform(test.begin(), test.end(), test.begin(), ::tolower); // 1) OK
std::transform(test.begin(), test.end(), test.begin(), std::tolower); // 2) Cryptic compile error
std::transform(test.begin(), test.end(), test.begin(), static_cast<int(*)(int)>(std::tolower)); // 3) Cryptic compile error. Seems OK with other compilers though
return 0;
}
所以:
- 为什么
::tolower
版本有效? - 为什么
std::tolower
在 std::transform 中不起作用? static_cast<int(*)(int)>(std::tolower))
到底想做什么?为什么它是否适用于GCC而不是Visual Studio 2013?- 那么,如何在 Visual Studio 2013 中使用 std::transform 中的
std::lower
呢?
首先,请注意,这些方法都没有以可移植的方式做正确的事情!问题是char
可以签名(通常是),但tolower()
的版本只接受正值!也就是说,您真的想使用如下所示的std::tolower()
:
std::transform(test.begin(), test.end(), test.begin(),
[](unsigned char c) { return std::tolower(c); });
(或者,当然,如果您坚持使用 C++03,请使用相应的函数对象)。使用具有负值的std::tolower()
(或::tolower()
)会导致未定义的行为。当然,这只在签署char
的平台上很重要,但这似乎是典型的选择。
要回答您的问题:
- 包含
<cctype>
时,通常从命名空间std
和全局命名空间中的标准 C 库中获取各种函数和类型。因此,使用::tolower
通常有效,但不能保证有效。 - 当包括
<locale>
时,有两个版本的std::tolower
可用,一个作为int(*)(int)
,一个作为char(*)(char, std::locale const&)
。当只使用std::tolower
编译器通常无法决定使用哪一个。 - 由于
std::tolower
不明确,因此使用static_cast<int(*)(int)>(std::tolower)
可以消除使用哪个版本的歧义。为什么将static_cast<...>()
与VC++一起使用失败,我不知道。 - 无论如何,您都不应该将
std::tolower()
与char
的序列一起使用,因为它会导致未定义的行为。在unsigned char
上使用内部使用std::tolower
的函数对象。
通常要快得多,因为内联函数对象是微不足道的,但内联函数指针就不那么简单了。编译器在函数指针的实际已知情况下内联使用函数指针变得越来越好,但当代编译器肯定并不总是通过函数指针内联函数调用,即使所有上下文都在那里。
std::tolower
在C++ 中重载,则在 <cctype>
中声明为
int tolower(int);
并且在<locale>
template<CharT> CharT tolower(CharT, const locale&);
所以当你说"std::tolower
"时,你会得到一个对重载函数的模糊引用。
- 为什么
::tolower
版本有效?
包含<cctype>
时,单参数重载将在命名空间std
中声明,也可能在全局命名空间中声明,具体取决于编译器。 如果包含<ctype.h>
则保证它包含在全局命名空间中,并且::tolower
将起作用(尽管请注意 Dietmar 关于何时不安全的观点)。来自 <locale>
的双参数重载永远不会在全局命名空间中声明,因此::tolower
从不引用双参数重载。
2. 为什么
std::tolower
在 std::transform 中不起作用?
见上文,这是一个重载的名称。
3.
static_cast<int(*)(int)>(std::tolower))
真正想做什么?
它告诉编译器您希望int std::tolower(int)
重载,而不是任何其他std::tolower
重载。
为什么它适用于GCC而不是Visual Studio 2013?
可能是因为你没有包含<cctype>
,或者(不太可能)它可能是Visual Studio的错误。
4. 那么,如何在 Visual Studio 2013 中使用
std::lower
std::transform
?
如果您知道只有值介于 0 和 127 之间的字符,则可以包含 <ctype.h>
并使用 ::tolower
(因为双参数版本未在全局命名空间中声明,仅在命名空间中声明 std
)或消除所需的静态强制转换的歧义。 强制转换的替代方法是使用局部变量:
typedef int (*tolower_type)(int);
tolower_type tl = &std::tolower;
std::transform(b, e, b, tl);
更安全且可移植的替代方法是使用自定义函数对象(或 lambda 表达式)安全地调用所需的重载:
std::transform(b, e, b, [](unsigned char i) { return std::tolower(i); });
这会将std::tolower
与参数一起使用,因此编译器可以执行重载解析来告知要调用哪个重载。 unsigned char
参数是为了确保我们永远不会将负值的char
传递给tolower(int)
,因为它具有未定义的行为。
有关更多详细信息,请参阅 http://gcc.gnu.org/onlinedocs/libstdc++/manual/strings.html#strings.string.simple。
- 将"libpqxx"与Visual Studio 2013链接/安装,以便与PostgrSQL建立C++连接
- Visual Studio 2013,错误 MSB8020:找不到 Visual Studio 2010 的生成工具
- 为什么在Visual Studio 2013上的std::this_thread::sleep_for上死锁
- 性能报告 (.vspx) 在 Visual Studio 2013 中未打开(显示损坏)
- 在 Visual Studio 2013 中使用零大小数组C++
- Visual Studio 2013 标头包含失败
- Visual studio 2013 和 g++ 7.1 中将 int 和 long 类型相乘时的 c++ 差异行为
- 在Visual Studio 2013中编译的STL列表代码在Visual Studio 2019中给出了错误.想知道原
- 错误 LNK2019: 未解析的外部符号 Visual Studio 2013 与 openCV
- cv:内存位置的异常 - 运行 openCV 代码 Visual Studio 2013 & Visual Studio 2017 - Windows 7
- 模块计算机类型和目标计算机类型 Visual Studio 2013
- 如何在Visual Studio 2013 Ultimate Edition中包含某个单词的每一行中插入断点
- 具有显式参数和大小的可变参数模板.Visual Studio 2013.
- 使用 Visual Studio 2013 编译 GDCM dlls 2.8.4 for Windows
- 基本字符串操作有问题 [c++, Visual Studio 2013]
- Visual Studio 2013中可能的C/C 编译器错误
- 在Visual Studio 2013上.Win32 应用和 CLR 应用
- 我正在尝试在Visual Studio 2013中编写我的第一个"Hello World"代码。为什么我会收到"IntelliSense: no operator message"和"error C2
- DLL不导出Visual Studio 2013 VB代码中的字符串
- 我们如何使用Visual Studio 2013访问C 中的更改编号