0

文字列から空白を削除しようとしています

line.erase(remove_if(line.begin(), line.end(), isspace), line.end()); 

しかし、Visual Studio 2010 (C++ Express) は教えてくれます

1   IntelliSense: no instance of function template "std::remove_if" matches the argument list   d:\parsertry\parsertry\calc.cpp 18

完全なソース

何故ですか?シンプルなコード

int main() {
    string line = "hello world   111    222";
    line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
    cout << line << endl;

    getchar();

    return 0;
}

機能が動作することを確認しますか?

それにもかかわらず、面白いことに、実行すると正しい結果が得られます。

4

3 に答える 3

1

Intellisense について質問しないでください。無視した方がよい場合もあります。パーサーまたはデータベースがどういうわけか台無しになったので、正しく動作しなくなりました。通常、再起動すると問題が解決します。

コードの形式が正しくないかどうかを本当に知りたい場合は、F7 を押してコンパイルしてください。

于 2012-10-25T13:26:05.380 に答える
0

とはisspace? インクルード ヘッダーと使用しているコンパイラによっては、コードがコンパイルされない可能性もあります。(IntelliSense についてはわかりませんが、すべての標準ヘッダーを見て、あいまいさを認識している可能性があります。)

標準には 2 つのisspace関数があり、1 つはテンプレートです。関数テンプレートを別の関数テンプレートのテンプレート引数に渡すと、テンプレート引数のisspace推定 を行うのに十分な情報がコンパイラにほとんど与えられませremove_ifん。テンプレートの実引数推定が成功した後、それを認識します。また、 でテンプレート引数推定を行うにremove_ifは、引数の型、つまり の型を知る必要があります。この型はisspace、そのオーバーロードを解決できるようになって初めてわかります。

(私はあなたの小さなコードがコンパイルされることに実際に驚いています: あなたは明らかに を含め<iostream>、通常は、関数 template をもたらす を<iostream>含め ます。)<locale>isspace

もちろん、関数テンプレートisspaceは 2 つの引数で呼び出さなければならないため、それが選択された場合、 のインスタンス化はremove_if コンパイルされません (ただし、コンパイラは remove_if関数を選択するまでインスタンス化を試みません)。また、isspacein <ctype.h>を渡すと未定義の動作になるため、char使用できません。通常の解決策は、ツール ボックス用の一連の述語オブジェクトを作成し、それらを使用することです。のみに関心がある場合は、次のようなものが機能するはずですchar

template <std::ctype<char>::mask m>
class Is : public std::unary_function<char, bool>
{
    std::locale myLocale;  //  To ensure lifetime of following...
    std::ctype<char> const* myCType;
public:
    Is( std::locale const& loc = std::locale() )
        : myLocale( loc )
        , myCType( &std::use_facet<std::ctype<char> >( myLocale ) )
    {
    }

    bool operator()( char ch ) const
    {
        return myCType->is( m, ch );
    }
};
typedef Is<std::ctype_base::space> IsSpace;

IsNot追加の typedef を追加して完全なセットを取得するのは簡単です。テンプレートを追加することも役立つことがわかりました。シンプルで、周囲の問題をすべて回避します。

于 2012-10-25T14:55:31.427 に答える
0

ソース コードは、Visual C++ 11.0 (Visual Studio 2012 に同梱されているコンパイラ) で警告なしにコンパイルされます。

Intellisense は独自のルールを使用するため、常に信頼できるとは限りません。

そうは言っても、オリジナルの 7 ビット ASCII を除くすべての文字セットでの使用isspace未定義の動作です。つまり、あなたがそれを選んだ非常に支持された答えは、ただのばかげたものです(驚くべきことではありません)。負の値と UB を避けるために、引数を (C ライブラリの)isspaceにキャストする必要があります。unsigned char

C99 §7.4/1 (N869 ドラフトから):

ヘッダー<ctype.h>は、文字のテストとマッピングに役立ついくつかの関数を宣言します。すべての場合において、引数は でありint、その値は として表現可能であるunsigned charか、マクロの値と等しくなければなりませんEOF。引数が他の値を持つ場合、動作は未定義です。

C 関数をラップする簡単な方法は次のとおりです。

bool isSpace( char const c )
{
    typedef unsigned char UChar;
    return !!::isspace( UChar( c ) );
}

なぜtypedefですか?

  1. そのような が既にある場合、コードを簡単に適応させることができますがtypedef、これは珍しいことではありません。

  2. コードがより明確になります。と

  3. C 構文のキャストを回避するため、正規表現やその他のパタ​​ーン マッチングを介して検索する際の誤検出を回避できます。

しかし、なぜ!!(否定演算子の二重適用) なのか? からへの自動暗黙的な変換があることを考慮すると? そして、変換が明示的であるべきだと絶対に感じているなら、それは であるべきではなく、ではないでしょうか?intboolstatic_cast!!

!! Visual C++ コンパイラからのばかげた警告を回避します。

「警告 C4800: 'int': 値を bool 'true' または 'false' に強制しています (パフォーマンス警告)」

そして、static_castその警告を止めません。Visual C++ は最もよく使用されるシステム、つまり Windows のメインの C++ コンパイラであるため、移植性を意図したすべてのコードでこれを行うことをお勧めします。

オーケー、でも、とにかく関数をラップしなければならないので…ヘッダーがはるかに柔軟な C++ (2 つの引数)関数を提供しているのに、なぜ古い C ライブラリisspace(単一引数) 関数を使用するのでしょうか?<locale>isspace

何よりもまず、古い Cisspace関数が質問で使用されているため、この回答で説明されている関数です。これを誤って行わない方法、つまり、未定義の動作を回避する方法に焦点を当ててきました。それを正しく行う方法について話し合うことは、それをまったく異なるレベルに引き上げます。

しかし、実際には、同じ名前の C++ レベル関数は壊れていると見なすことができます。これは、g++ コンパイラでは最近まで (そしておそらく g++ 4.7.2 でも最近チェックしていません)、C ロケール メカニズムのみであったためです。 Windowsでは機能しましたが、C++レベルのものは機能しませんでした. g++ がワイド ストリームをサポートするようになったため、修正された可能性がありますが、わかりません。とにかく、C ライブラリisspace関数は、より移植性が高く、一般的に Windows で動作することに加えて、より単純で、より効率的であると私は信じています(ただし、効率のために、重要と見なされる場合は常に測定する必要があります!)。

コメントで上記の質問を (本質的に) 行ってくれた James Kanze に感謝します。

于 2012-10-25T13:28:59.413 に答える