[英]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? std::lower
和Visual Studio 2013呢? 首先,請注意,這些方法都不是以便攜方式做正確的事情! 問題是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)
消除了使用哪個版本的歧義。 為什么在VC ++中使用static_cast<...>()
失敗,我不知道。 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
std::lower
呢?
如果您知道只有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 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.