最悪の選択肢から最良の選択肢へと進む選択肢のリストを見てみましょう。それらをここにリストし、以下で説明します。
transform(cbegin(s), cend(s), begin(s), ::tolower)
transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
質問のコードは、transform(s.begin(), s.end(), s.begin(), tolower)
次のようなエラーを生成します。
への呼び出しに一致する関数がありませんtransform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)
「未解決のオーバーロードされた関数型」を取得していた理由は、名前空間に 2 つtolower
の s があるためです。std
locale
ライブラリが定義するtemplate <typename T> T tolower(T, const locale&)
cctype
ライブラリが定義するint tolower(int)
1はdavka が提供するソリューションです。がグローバル名前空間で定義されていないlocale
という事実を利用して、エラーに対処します。tolower
状況によっては検討に値する場合がありますlocale
。ここで s のtolower
比較を見つけることができます: C++ でどの tolower?tolower
残念ながら、1は がグローバル名前空間で定義されていることにcctype
依存しています。tolower
そうではない理由を見てみましょう。
C++ では非推奨になっているため、正しく使用#include <cctype>
しています: http://en.cppreference.com/w/cpp/header#include <ctype.h>
しかし、C++ 標準では、ヘッダーの宣言の D.3[depr.c.headers]2 に次のように記載されています。
これらの名前が最初に名前空間の名前空間スコープ (3.3.6) 内で宣言または定義std
され、次に明示的な using 宣言 (7.3.3) によってグローバル名前空間スコープに注入されるかどうかは指定されていません。
したがって、コードが実装に依存しないことを保証できる唯一の方法は、tolower
fromを使用することnamespace std
です。2はDavid Rodríguez-dribeas によって提供されたソリューションです。static_cast
次のことができるという事実を活用します。
特定の型への関数からポインターへの変換を実行することにより、関数のオーバーロードを明確にするために使用されます
先に進む前に、少しわかりにくい場合は、ここint (*)(int)
で関数ポインターの構文について詳しく読むことができることをコメントさせてください。
悲しいことに、 の入力引数にはもう 1 つの問題があります。tolower
unsigned char として表現できず、EOF と等しくない場合、動作は未定義です
string
タイプの要素を使用するを使用しています: char
。char
具体的には 7.1.6.2[dcl.type.simple]3の標準状態:
型のオブジェクトがchar
符号付きまたは符号なしの量として表されるかどうかは実装定義です。指定子は、オブジェクトに署名をsigned
強制しますchar
したがって、実装で a が achar
を意味するように定義されている場合、 1と2signed char
の両方で、負の数に対応するすべての文字に対して未定義の動作が発生します。(ASCII 文字エンコーディングが使用されている場合、負の数に対応する文字は拡張 ASCIIです。)
unsigned char
未定義の動作は、入力をに渡す前に に変換することで回避できますtolower
。3は、値を受け取るラムダを使用してそれを実現し、unsigned char
それをtolower
暗黙的に に変換して渡しint
ます。
文字エンコーディングに関係なく、準拠したすべての実装で定義された動作を保証するには、transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
または同様のものを使用する必要があります。