32

コードを考えると:

#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>)

「未解決のオーバーロードされた関数型」とはどういう意味ですか?

を私が書いた関数に置き換えるtolowerと、エラーが発生しなくなります。

4

5 に答える 5

28

最悪の選択肢から最良の選択肢へと進む選択肢のリストを見てみましょう。それらをここにリストし、以下で説明します。

  1. transform(cbegin(s), cend(s), begin(s), ::tolower)
  2. transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
  3. 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

  1. localeライブラリが定義するtemplate <typename T> T tolower(T, const locale&)
  2. cctypeライブラリが定義するint tolower(int)

1davka が提供するソリューションです。がグローバル名前空間で定義されていない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です。2David Rodríguez-dribeas によって提供されたソリューションですstatic_cast次のことができるという事実を活用します。

特定の型への関数からポインターへの変換を実行することにより、関数のオーバーロードを明確にするために使用されます

先に進む前に、少しわかりにくい場合は、ここint (*)(int)で関数ポインターの構文について詳しく読むことができることをコメントさせてください。


悲しいことに、 の入力引数にはもう 1 つの問題があります。tolower

unsigned char として表現できず、EOF と等しくない場合、動作は未定義です

stringタイプの要素を使用するを使用しています: charchar具体的には 7.1.6.2[dcl.type.simple]3の標準状態:

型のオブジェクトがchar符号付きまたは符号なしの量として表されるかどうかは実装定義です。指定子は、オブジェクトに署名をsigned強制しますchar

したがって、実装で a が acharを意味するように定義されている場合、 12signed charの両方で、負の数に対応するすべての文字に対して未定義の動作が発生します。(ASCII 文字エンコーディングが使用されている場合、負の数に対応する文字は拡張 ASCIIです。)

unsigned char未定義の動作は、入力をに渡す前に に変換することで回避できますtolower3は、値を受け取るラムダを使用してそれを実現し、unsigned charそれをtolower暗黙的に に変換して渡しintます。

文字エンコーディングに関係なく、準拠したすべての実装で定義された動作を保証するには、transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })または同様のものを使用する必要があります。

于 2016-05-25T13:06:15.997 に答える
28

を使ってみてください::tolower。これで問題は解決しました。

于 2011-04-04T13:48:07.760 に答える
23

この問題は、おそらく の複数のオーバーロードに関連して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 );
于 2011-04-04T13:38:07.253 に答える
7

David はすでに問題を特定しています。

  • <cctype>int tolower(int c)
  • <locale>template <typename charT> charT tolower(charT c, locale const& loc)

最初のものを使用する方がはるかに簡単ですが、符号付き文字で下位ASCII (0-127) 以外のものを処理するとすぐに、(残念ながら) 未定義の動作になります。ところで、charunsigned として定義することをお勧めします。

テンプレートバージョンはいいでしょうがbind、2番目のパラメーターを提供するために使用する必要があり、それは醜いものになるでしょう...

それでは、Boost String Algorith m ライブラリを紹介してもよろしいでしょうか?

そしてもっと重要なこと: boost::to_lower:)

boost::to_lower(s);

表現力が望ましい。

于 2011-04-04T19:22:11.763 に答える
4

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

したがって、 (from ) とルート (from ) の名前空間tolowerの両方に存在するように見えます。が何をするのかわかりません。std<cctype><ctype.h>#pragma

于 2011-04-04T13:49:55.163 に答える