2016-11-27 6 views
2

入力と出力のために私自身のマニピュレータを記述したいとしましょう。自分のマニピュレータを書くには?

cin >> mymanip >> str; 

または

cout << mymanip << str; 

私はmymanipがないことを望むことは、私が入力から読み込まれ、1つの文字列に結果を代入し caracters トグルケースです。

「QwErTy」と入力すると、文字列に「qWeRtY」が表示されます。

これは1つの機能では非常に基本的な作業ですが、私はマニピュレータについて詳しく知りたいと思います。

誰かが手がかりを与えることはできますか?

ありがとうございます。

+0

http://stackoverflow.com/questions/21358150/c-changing-lower-case-letters-in-a-string-function-againおよびhttp://stackoverflow.com/questions/313970をご覧ください。/how-to-convert-stdstring-to-lower-case –

+2

@payamsbr、リンクは私の質問に答えません。私が知りたいのは、マニピュレータを作成する方法です。私はちょうど例としてトグル文字列を言及しました。 – user7140484

答えて

2

方法はちょっと難しいですが、それを行うことができます、ストリームのための独自のマニピュレータを追加することができます。

まず、あなたの必要性あなたのtoogle:

class toogle_t {}; 
constexpr toogle_t toogle; 

次 - のostreamのバージョン(IStreamのためのケースは非常に似ている...):

のostreamにtoogleを入れた後 - あなたには、いくつかの特別なオブジェクトが必要:

struct toogled_ostream 
{ 
    std::ostream& os; 
}; 

inline toogled_ostream operator << (std::ostream& os, toogle_t) 
{ 
    return { os }; 
} 

は、誰かが間違った場所にtoogleを置く可能性があることを、注意してください:cout << toogle << 123 - それはordinとして他のすべてのタイプのために働く必要がありますので、進ストリーム:

template <typename T> 
std::ostream& operator << (toogled_ostream tos, const T& v) 
{ 
    return tos.os << v; 
} 

ので - (charconst char*std::stringなど)char型のためにあなたのトグルオーバーロードを書きます。私はcharのためにあなたのバージョンを与えている - 「長い」タイプのバージョンを書くために問題になることはありません。demo作業

std::ostream& operator << (toogled_ostream tos, char v) 
{ 
    char c = std::isupper(v) ? std::tolower(v) 
          : std::islower(v) ? std::toupper(v) : v; 
    return tos.os << c; 
} 

+0

空のクラス=>クラスtoogle_t {};の使用方法私のコンパイラではconstexprのエラーが出る – user7140484

+0

1)古いコンパイラ(C++ 11ではなく)があり、代わりに 'const'を使うかもしれません。2)これは単なるタグクラスです3)はい、次の入力のために働きます - あなたはsometingを印刷するたびにそれを繰り返す必要があります: 'cout << toogle << c1 << toogle << c2' - これは特別なことではありません... – PiotrNycz

+0

私が書いたように、 'std :: ostream&operator <<(toogled_ostream tos、const char * str)'と 'std :: ostream&operator <<(toogled_ostream tos、const std :: string&str) ' – PiotrNycz

5

マニピュレータが行うすべては、std::ios_baseベースクラスの対応するビットを設定します。

たとえば、std::setprecision()マニピュレータは、操作されたストリーム上の単純にinvokes std::ios_base::precision()です。

inline _Setprecision setprecision(int __n) 
    { return { __n }; } 

std::setprecision()内部std::_Precisionオブジェクトを返す:

std::setprecision()の実装では、GCCのヘッダー(C++ライブラリテンプレートの実装のための希少)で、ほとんど読み取り可能です。その後、>>のための単純なテンプレートのオーバーロード(と似ている<<オペレータ、)std::_Precisionオブジェクトのオペレータは、魔法の残りハンドル:あなたのケースでは

template<typename _CharT, typename _Traits> 
    inline basic_istream<_CharT, _Traits>& 
    operator>>(basic_istream<_CharT, _Traits>& __is, _Setprecision __f) 
    { 
     __is.precision(__f._M_n); 
     return __is; 
    } 

を、にはビットが存在しませんstd::ios_baseあなたの希望する入出力変換を実装するクラスです。そのため、マニピュレータ自体はここでは機能しません。 std::[io]stream

  1. カスタムサブクラス、std::streambufのカスタムサブクラスを使用しています:あなたが何をしようとして

    は全く異なる、より複雑な、アプローチが必要です。

  2. サブクラスは、連鎖ストリームから読み書きを行い、記述したように入力または出力を変換します。

  3. カスタムサブクラスから読み書きすると、連鎖ストリームからの読み書きが終了し、それに応じてデータが変換されます。

2

これはできません。あなたの代わりに何ができるか、それはより便利そうでない場合よりも、物事を行うことができ、すなわちマニピュレータがしか糖衣構文いわゆるある、すなわち

std::cout << toggle(str); 
std::cin >> toggle(str); 

引数として文字列を取るマニピュレータは、あります。例えば、

std::cout << std::setw(5) << x <<; 

std::cout.width(5); 
std::cout << x; 

と同じ操作を行うが、それは他の<<の操作と一緒に連鎖させることを可能にするように、より便利であるだろう。

これで、必要なもの(大文字と小文字を入れ替える)のフォーマットがサポートされていないため、そのための構文的な砂糖を提供する方法もありません。

しかし、マニピュレータがあなたの文字列を引数として取ることができれば、もちろん、マニピュレータの標準的な実装方法で実装したいものを実現できます。例えば、

struct toggle_output 
{ std::string const&str; } 

inline toggle_output toggle(std::string const&str) 
{ return {str}; } 

inline std::ostream& operator<<(std::ostream&out, toggle_output const&t) 
{ 
    for(auto c:t.str) 
    if  (std::islower(c)) out<<std::toupper(c); 
    else if(std::isupper(c)) out<<std::tolower(c); 
    else      out<<c; 
    return out; 
} 

struct toggle_input 
{ std::string &str; } 

inline toggle_input toggle(std::string&str) 
{ return {str}; } 

inline std::istream& operator>>(std::istream&in, toggle_input &t) 
{ 
    in >> t.str; 
    for(auto&c:t.str) 
    if  (std::islower(c)) c=std::toupper(c); 
    else if(std::isupper(c)) c=std::tolower(c); 
    return in; 
} 

はまた

(混乱を避けるために)必要があるかもしれない
inline std::ostream& operator<<(std::ostream&out, toggle_input const&t) 
{ return out<<toggle_output(t.str); } 
1

他の回答は説明として、マニピュレータは、単に既存のstd::ios_baseの機能を模倣します。私は、これはマニピュレータを呼び出すことができるかはわからないけれども

、あなたの問題の簡単な解決策があります:

ある
struct toggle_in_helper 
{ 
    std::string & res; 
}; 

toggle_in_helper toggle (std::string & res) 
{ 
    return {res}; 
} 

std::istream & operator >> (std::istream & in, toggle_in_helper h) 
{ 
    in >> h.res; 
    for (auto & c : h.res) 
     // toggle the case of 'c' 
     ; 
    return in; 
} 

は、我々は仕事をして、オーバーロードoperator >>とヘルパークラスtoggle_in_helperを作成します。

関連する問題