コードを考える:
_#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s("ABCDEFGHIJKL");
transform(s.begin(),s.end(),s.begin(),tolower);
cout<<s<<endl;
}
_
エラーが発生します:
transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)
の呼び出しに一致する関数がありません
"unresolved overloaded function type"はどういう意味ですか?
tolower
を私が作成した関数に置き換えても、エラーは発生しなくなりました。
::tolower
を使用してみてください。これで問題が解決しました。
問題はおそらくtolower
の複数のオーバーロードに関連しており、コンパイラーは1つを選択できません。これを修飾して特定のバージョンを選択するか、明確にするためにキャストされた関数ポインターを提供する必要がある場合があります。 tolower
関数は、<locale>
ヘッダーと<cctype>
に存在できます(複数の異なるオーバーロード)。
試してください:
int (*tl)(int) = tolower; // Select that particular overload
transform(s.begin(),s.end(),s.begin(),tl );
これはキャストを使用して1行で行うことができますが、おそらく読みにくいでしょう。
transform(s.begin(),s.end(),s.begin(),(int (*)(int))tolower );
最悪のものから始まり、最高のものに移動するオプションのリストを見てみましょう。それらをここにリストし、以下で説明します。
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>)
の呼び出しに一致する関数がありません
「未解決のオーバーロードされた関数型」を取得した理由は、tolower
名前空間に2つのstd
sがあるためです。
locale
ライブラリは template <typename T> T tolower(T, const locale&)
を定義しますcctype
ライブラリは int tolower(int)
を定義します1は davkaが提供するソリューション です。 locale
のtolower
がグローバル名前空間で定義されていないという事実を利用して、エラーに対処します。
状況によっては、locale
のtolower
を検討する価値があります。 tolower
sの比較は、次の場所にあります。 C++ではどちらが低いですか?
残念ながら1は、cctype
のtolower
がグローバル名前空間で定義されていることに依存しています。それがそうではないかもしれない理由を見てみましょう:
_#include <cctype>
_をC++で廃止されたため、_#include <ctype.h>
_を正しく使用しています: http://en.cppreference.com/w/cpp/header
ただし、C++標準では、ヘッダーの宣言のD.3 [depr.c.headers] 2に次のように記載されています。
これらの名前が最初に名前空間
std
の名前空間スコープ(3.3.6)内で宣言または定義され、次に明示的なusing宣言(7.3.3)によってグローバル名前空間スコープに注入されるかどうかは指定されていません。
したがって、コードが実装に依存しないことを保証できる唯一の方法は、_namespace std
_のtolower
を使用することです。 2は DavidRodríguez-dribeasが提供するソリューション です。 _static_cast
_ ができることを利用しています:
特定の型への関数からポインターへの変換を実行して、関数のオーバーロードを明確にするために使用されます
先に進む前に、int (*)(int)
が少しわかりにくい場合は、関数ポインタの構文 here について詳しく読むことができるとコメントさせてください。
悲しいことに 他の1つの問題 が存在する場合、tolower
の入力引数があります:
Unsigned charとして表現できず、EOFと等しくない、動作は未定義
タイプstring
のエレメントを使用するchar
を使用しています。特にchar
の標準状態は7.1.6.2 [dcl.type.simple] 3です。
char
型のオブジェクトが符号付きまたは符号なしの数量として表されるかどうかは、実装によって定義されます。signed
指定子はchar
オブジェクトを強制的に署名します
したがって、実装でchar
が_signed char
_を意味するように定義した場合、1と2は、負の数値に対応するすべての文字に対して未定義の動作になります。 (ASCII文字エンコードが使用されている場合、負の数に対応する文字は 拡張ASCII です。)
未定義の動作は、tolower
に渡す前に入力を_unsigned char
_に変換することで回避できます。 3は、値によって_unsigned char
_を受け入れるラムダを使用してそれを実行し、それをtolower
に渡して暗黙的にint
に変換します。
文字エンコーディングに関係なく、すべての準拠した実装で定義済みの動作を保証するには、transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })
または類似のものを使用する必要があります。
デビッドはすでに問題、すなわち以下の間の矛盾を特定しました:
<cctype>
_ のint tolower(int c)
<locale>
_ のtemplate <typename charT> charT tolower(charT c, locale const& loc)
最初のものを使用する方がはるかに簡単ですが、符号付き文字で小文字のASCII(0〜127)以外のものを処理するとすぐに(残念ながら)未定義の動作になります。 ところで、私はchar
を符号なしとして定義することをお勧めします。
テンプレートのバージョンはいいですが、2番目のパラメーターを提供するためにbind
を使用する必要があり、醜いことにバインドされています...
では、 Boost String Algorith mライブラリを紹介してもよいですか?
そしてもっと重要なこと: _boost::to_lower
_ :)
_boost::to_lower(s);
_
表現力が望ましい。
Gcc 4.2.1の<ctype>
ヘッダーを参照すると、次のように表示されます。
// -*- C++ -*- forwarding header.
// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
// Free Software Foundation, Inc.
...
#ifndef _GLIBCXX_CCTYPE
#define _GLIBCXX_CCTYPE 1
#pragma GCC system_header
#include <bits/c++config.h>
#include <ctype.h>
// Get rid of those macros defined in <ctype.h> in lieu of real functions.
#undef isalnum
#undef isalpha
...
#undef tolower
#undef toupper
_GLIBCXX_BEGIN_NAMESPACE(std)
using ::isalnum;
using ::isalpha;
...
using ::tolower;
using ::toupper;
_GLIBCXX_END_NAMESPACE
#endif
したがって、tolower
は、std
(<cctype>
から)とルート(<ctype.h>
から)の両方のネームスペースに存在するようです。 #pragma
の意味がわかりません。