8

文字列内のすべての数値を最短のコードで数えたい。私はそのように試しました:

#include <string>
#include <algorithm>

unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), isdigit);
}

エラーメッセージは次のとおりです。

a.cc: In function ‘unsigned int countNumbers(std::string)’:
a.cc:5:45: error: no matching function for call to ‘count_if(std::basic_string<char>::const_iterator, std::basic_string<char>::const_iterator, <unresolved overloaded function type>)’
a.cc:5:45: note: candidate is:
/usr/include/c++/4.6/bits/stl_algo.h:4607:5: note: template<class _IIter, class _Predicate> typename std::iterator_traits<_InputIterator>::difference_type std::count_if(_IIter, _IIter, _Predicate)

count_if()が次のような関数を必要としていることを私は知っています:bool(* f)(char); 3番目の引数として、関数をキャストしようとしました。

unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), reinterpret_cast<bool (*)( char )>(isdigit));
}

エラーメッセージは次のとおりです。

a.cc: In function ‘unsigned int countNumbers(std::string)’:
a.cc:5:80: error: overloaded function with no contextual type information

同じコンパイルエラーが発生する、もう少し長いバージョンも試しました。

unsigned countNumbers(const std::string s) {
    typedef bool ( * f_ptr )( char );
    f_ptr ptr = reinterpret_cast<f_ptr>(isdigit);
    return count_if(s.begin(), s.end(), ptr);
}

私が避けたい解決策は、アダプターとなる関数を作成することです。

#include <string>
#include <algorithm>

bool is_digit(char c) {
    return isdigit(c);
}

unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), is_digit);
}

私の質問は、アダプタ関数を作成せず、ラムダ式を使用せずに、bool(* f)(int)を必要とするstd ::アルゴリズムの関数で関数int(* f)(int)をどのように使用できるかです。

問題を解決する方法を知ったときに解決される問題が他にもあります。例:

  • 文字列が印刷可能かどうかを確認します:find_if_not(s.begin()、s.end()、isprint)
  • 文字列に「、。!?...」が含まれているかどうかを確認します:find_if(s.begin()、s.end()、ispunct)など...

std :: Algorithmsのおかげで、標準のC ++でより多くの文字列の可能性を実現する方法を知りたいだけです。インターネットで長い間検索していたのですが、同様の問題が見つかりましたが、解決策は見つかりませんでした。

4

4 に答える 4

6

静的キャストを使用して関数を解決できます。あるいは、これがあなたがたくさんやりたいことであるならば、あなたはそれを解決するためにテンプレートを使うことができます:

#include <string>
#include <cctype>
#include <algorithm>

unsigned count(const std::string& s) {
  return std::count_if(s.begin(), s.end(), static_cast<int(*)(int)>(std::isdigit));
}

template <int(*Pred)(int)> 
unsigned foo(const std::string& s) {
  return std::count_if(s.begin(), s.end(), Pred);
}

int main() {
  count("");
  foo<std::isdigit>("");
  foo<std::isprint>("");
}

static_castあいまいさを解決する「通常の」方法です。これは常に期待どおりのことを行い、より大きな表現の一部にすることができます。

于 2013-02-23T11:22:37.663 に答える
3

関数ポインタを使用して型を解決します。

unsigned countNumbers(const std::string s) {
    int (*isdigit)(int) = std::isdigit;
    return count_if(s.begin(), s.end(), isdigit);
}

を含めることを忘れないでください<cctype>。(デモ

于 2013-02-23T11:19:25.143 に答える
2

私は以下も機能することを発見しました:

    #include <ctype.h>
    count_if(s.begin(), s.end(), ::isdigit); //explicitly select the C version of isdigit 

しかし、Cバージョンがマクロではなく関数として定義されている場合にのみ機能することを理解する必要があります

したがって、std :: isdigitのstatic_castは、プラットフォームの中で最高のポータブルソリューションになる可能性があります。

于 2014-07-29T03:49:40.340 に答える
2

あいまいさを修正するための他の2つの解決策を示します<locale> std::isdigit

  1. ラムダ式を使用します:

    std::count_if(s.begin(), s.end(), [](char c){ return std::isdigit(c); })

または明示的なキャストを使用:

std::count_if(s.begin(), s.end(), [](char c){ return std::isdigit(static_cast<int>(c)) != 0; })
  1. 明示的なテンプレートタイプを使用します(イテレータータイプも記述する必要があります)。

std::count_if<std::string::const_iterator, int(*)(int)>(s.begin(), s.end(), std::isdigit)

于 2018-02-22T18:46:04.497 に答える