1. ホーム

[C++ エラー処理] transform の呼び出しに一致する関数がありません。

2022-02-12 09:41:36

このエラーはとても愚かなことだと思うのですが、どうでしょうか。状況は以下の通りです。

#include 
#include 
#include 

using namespace std;

int main (int argc, char * const argv[]){
  string str = "Hello";
  transform(str.begin(), str.end(), str.begin(), toupper);
  cout << str << endl;
  
  return 0;
}

プログラムの意味は簡単で、Hello allを大文字に変換してこいということです。

コンパイルが通らない。

$ g++ -g -Wall strToUpper.cpp -o strToUpper
strToUpper.cpp: In function 'int main(int, char* const*)':
strToUpper.cpp:9: error: no matching function for call to 'transform(__gnu_cxx::__normal_iterator, std::allocator > >, __gnu _cxx::__normal_iterator, std::allocator > >, __gnu_cxx::__normal_iterator, std::allocator > >, )'</CHAR*,> & lt;/CHAR*,></CHAR*,>

その後、原因は以下のように特定されました。

この関数の定義を見てみよう。

template OutIter transform(InIter start, InIter end, OutIter result, Func unaryFunc)

Linuxでは、toupperを関数ではなく、マクロとして実装しています。
/usr/lib/syslinux/com32/include/ctype.h:

/* 注:unsignedへの偶発的な昇格を避けるため、これは16進数ではなく10進数です */ 
#define _toupper(__c) ((__c) & ~32) 
#define _tolower(__c) ((__c) | 32)

__ctype_inline int toupper(int __c) 

return islower(__c) ? _toupper(__c) : __c; 
}

__ctype_inline int tolower(int __c) 

return isupper(__c) ? _tolower(__c) : __c; 
}

解決策は3つあります。

1. グローバル名前空間に実装された関数(マクロではない)があるため、名前空間を明示する。これは必ずしもうまくいかないが、私のg++環境では問題ない。

transform(str.begin(), str.end(), str.begin(), ::toupper) とします。

2. 自作ラッパーから関数を書き出す

inline charToUpper(char c) 

    return std::toupper(c); 
}

3. 強制変換:toupper を、戻り値が int で引数が int のみの関数ポインタに変換します。

transform(str.begin(), str.end(), str.begin(), (int (*)(int))toupper);

著者 グヌフック
プロヴァンス http://www.cnblogs.com/gnuhpc/