簡體   English   中英

std :: tolower和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;
}

所以:

  1. 為什么::tolower版本正在運行?
  2. 為什么std::tolower不能在std :: transform中工作?
  3. 什么static_cast<int(*)(int)>(std::tolower))真的想要做什么? 為什么它適用於GCC而不適用於Visual Studio 2013?
  4. 我怎么能在std :: transform中使用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平台,但這似乎是典型的選擇。

回答你的問題:

  1. 當包含<cctype>您通常會在命名空間std以及全局命名空間中從標准C庫中獲取各種函數和類型。 因此,使用::tolower通常可以工作但不能保證工作。
  2. 當包含<locale> ,有兩個版本的std::tolower可用,一個是int(*)(int) ,另一個是char(*)(char, std::locale const&) 當僅使用std::tolower ,編譯器通常無法決定使用哪一個。
  3. 由於std::tolower不明確,因此使用static_cast<int(*)(int)>(std::tolower)消除了使用哪個版本的歧義。 為什么在VC ++中使用static_cast<...>()失敗,我不知道。
  4. 你不應該將std::tolower()char序列一起使用,因為它會導致未定義的行為。 unsigned char上使用std::tolower內部的函數對象。

值得注意的是,使用函數對象而不是函數指針通常快得多,因為內聯函數對象是微不足道的,但內聯函數指針並不簡單。 編譯器在內聯函數指針的過程中越來越好,其中函數實際上是已知的,但是當前編譯器當然並不總是通過函數指針內聯函數調用,即使所有上下文都存在。

std::tolower在C ++中重載,它在<cctype>聲明為

int tolower(int);

以及<locale>中的

template<CharT> CharT tolower(CharT, const locale&);

所以當你說“ std::tolower ”時,你會得到一個對重載函數的模糊引用。

  1. 為什么::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM