最悪の選択肢から最良の選択肢へと進む選択肢のリストを見てみましょう。それらをここにリストし、以下で説明します。
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) によってグローバル名前空間スコープに注入されるかどうかは指定されていません。
したがって、コードが実装に依存しないことを保証できる唯一の方法は、tolowerfromを使用すること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); })または同様のものを使用する必要があります。