4

入力と出力用に独自のマニピュレータを書きたいとしましょう。

cin >> mymanip >> str;

また

cout << mymanip << str;

mymanip がしたいことは、入力から読み取った文字の大文字と小文字を切り替えて、結果を 1 つの文字列に割り当てることです。

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

これは 1 つの機能を持つ非常に基本的なタスクですが、マニピュレーターについてもっと学びたいと思っています。

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

ありがとうございました。

4

4 に答える 4

6

マニピュレータが行うことは、std::ios_base基本クラスで対応するビットを設定することだけです。

たとえば、マニピュレータは、操作されたストリームでstd::ios_base::precision() を呼び出すstd::setprecision()だけです。

の実装はstd::setprecision()、gcc のヘッダーでほぼ読み取り可能です (C++ ライブラリ テンプレートの実装ではまれです)。

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

std::setprecision()内部std::_Precisionオブジェクトを返します。次に、オブジェクトのオペレーター>>(および同様のオペレーター)の単純なテンプレート オーバーロードが、残りの魔法を処理します。<<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クラスには、目的の入出力変換を実装するビットはありません。そのため、マニピュレータ自体はここでは機能しません。

あなたがやろうとしていることは、まったく異なる、より複雑なアプローチを必要とします:

  1. のカスタム サブクラスstd::[io]streamを使用する のカスタム サブクラスstd::streambuf

  2. サブクラスはstd::streambuf、チェーンされたストリームから読み取りまたは書き込みを行い、説明したように入力または出力を変換します。

  3. カスタム サブクラスからの読み取りまたは書き込みは、連鎖ストリームからの読み取りまたは書き込みになり、それに応じてデータが変換されます。

于 2016-11-27T22:25:51.513 に答える
4

方法は少しトリッキーですが、ストリーム用の独自のマニピュレータを追加することで実行できます。

まず、トグルが必要です:

class toggle_t {};
constexpr toggle_t toggle;

次 - のバージョンostream(のケースistreamは非常に似ています...):

toggle- に配置した後ostream、特別なオブジェクトが必要です。

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

inline toggled_ostream operator << (std::ostream& os, toggle_t)
{
    return { os };
}

誰かがtoggle間違った場所に置く可能性があることに注意してください: cout << toggle << 123- したがって、通常のストリームとして他のすべてのタイプで機能するはずです:

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

そのため、char 型 ( charconst char*、 などstd::string) の場合は、トグル オーバーロードを記述します。私はあなたにバージョンを与えていますchar- 「より長い」タイプのバージョンを書くことは問題ではないはずです:

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

作業デモ

于 2016-11-27T23:14:21.650 に答える
3

それをしてはいけない。代わりにできることは、文字列を引数として取るマニピュレータです。

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); }
于 2016-11-27T22:27:08.673 に答える
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;
}

つまり、仕事をtoggle_in_helperするオーバーロードされたヘルパー クラスを作成します。operator >>

于 2016-11-27T22:38:01.087 に答える