C++ std::tolower和Visual Studio 2013
我试图了解如何使用C++ std::tolower和Visual Studio 2013,c++,visual-studio,c++11,C++,Visual Studio,C++11,我试图了解如何使用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::to
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;
}
#包括
#包括
#包括
#包括
int main()
{
std::string test=“Hello World”;
std::locale loc;
用于(自动和控制:测试)
{
c=标准::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)神秘的编译错误
std::transform(test.begin()、test.end()、test.begin()、static_cast(std::tolower));//3)神秘的编译错误。不过其他编译器似乎没有问题
返回0;
}
因此:
::tolower
版本正在运行李>
std::tolower
在std::transform中不起作用李>
std::lower
<>代码> STD::ToWoW在C++中被重载,在<代码> <代码>中声明为
int tolower(int);
template<CharT> CharT tolower(CharT, const locale&);
以及在
中作为
int tolower(int);
template<CharT> CharT tolower(CharT, const locale&);
更安全和可移植的替代方法是使用自定义函数对象(或lambda表达式)安全地调用所需的重载:
std::transform(b, e, b, [](unsigned char i) { return std::tolower(i); });
这将使用带有参数的std::tolower
,因此编译器可以执行重载解析来告诉您要调用哪个重载。参数为unsigned char
,以确保我们不会将带有负值的char
传递给tolower(int)
,因为这具有未定义的行为
请参阅以了解更多详细信息。首先,请注意,这些方法中没有一种能以可移植的方式做正确的事情!问题是,
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
被签名的平台上才重要,然而,这似乎是典型的选择
回答您的问题:
时,通常会从命名空间std
以及全局命名空间中的标准C库中获得各种函数和类型。因此,使用::tolower
正常工作,但不能保证工作正常
时,有两个版本的std::tolower
可用,一个为int(*)(int)
,另一个为char(*)(char,std::locale const&)
。当只使用std::tolower时,编译器通常无法决定使用哪一个std::tolower
不明确,因此使用static_cast(std::tolower)
可以消除使用哪个版本的歧义。我不知道为什么在VC++中使用static\u cast()
失败了std::tolower()
与char
s序列一起使用,因为这将导致未定义的行为。在无符号字符上内部使用std::tolower
使用函数对象
值得注意的是,使用函数对象而不是函数指针通常要快得多,因为内联函数对象很简单,而内联函数指针则不那么简单。编译器在函数实际已知的地方内联函数指针的使用越来越好,但当代编译器肯定不会总是通过函数指针内联函数调用,即使所有上下文都在那里。您是否尝试过包含
头、输出、Oo'^^^但是,为什么它与GCC一起工作?@Korchkidu,因为在GCC中,您包含的另一个头恰好包含
。千万不要误以为“它恰好与一个编译器一起工作”,因为这意味着代码实际上是正确的,尤其是关于包含其他库内部头的头。@JonathanWakely:谢谢,确实很清楚。你应该知道,不要建议人们将
函数与char
s一起使用!我不知道这是否也适用于VS2013,但VS2012的文档指出,除非isupper返回非零,否则在ctype.h中声明的tolower是不安全的,这意味着在转换中使用它需要对序列中的每个元素在isupper上进行显式测试。我知道我确实看到了大量忽略此约束的代码,但我很好奇这里是否有人对此有任何见解。@Neutrino:C标准(ISO/IEC 9899:2011;早期版本与我所知相同)在7.4.2.1第3段(返回)中对此主题的表述如下:“如果参数是isupper
为真的字符,并且有一个或多个由当前区域设置指定的对应字符,islower
为真,则tolower
函数返回一个对应字符(对于任何给定区域设置,始终相同);否则,参数将原封不动地返回。“除了作为一个有效的无符号字符
值之外,我看不到对参数的任何约束。Visual Studio是否遵守该标准,或者如其文档所示,是否添加了额外的非标准一致约束。这里非常清楚地指出,如果isupper没有为参数返回true,那么结果可能是“意外的”,不管这意味着什么@中微子:我不知道MSVC++是否有符合标准的tolower
实现。不过,我想他们会的。