入出力の書式化とマニピュレータ 解答ページ | Programming Place Plus C++編【標準ライブラリ】 第30章

トップページC++編

C++編で扱っている C++ は 2003年に登場した C++03 という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14 -> C++17 -> C++20 と更新されており、今後も 3年ごとに更新されます。
なかでも C++11 での更新は非常に大きなものであり、これから C++ の学習を始めるのなら、C++11 よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。

問題①

問題① フィールドの幅が 10 で、つねに右寄せに出力する myformatマニピュレータを自作してください。


std::endlマニピュレータの実装を参考にして、自作の myformat関数を定義します。

#include <iostream>

namespace {
    template <typename T, typename Traits>
    std::basic_ostream<T, Traits>& myformat(std::basic_ostream<T, Traits>& os)
    {
        os.width(10);
        os.setf(std::ios::right, std::ios::adjustfield);
        return os;
    }
}

int main()
{
    std::cout << "xyz" << std::endl;
    std::cout << myformat << "xyz" << std::endl;
}

実行結果:

xyz
       xyz

問題②

問題② myformatマニピュレータを改造して、以下のようにフィールドの幅を指定できるようにしてください。

std::cout << myformat(10) << "xyz" << std::endl;


引数があると、標準で定義されている operator<< に渡す関数ポインタの型と適合しないため、関数のままでは実装できません。

解決方法の1つとしては、マニピュレータをクラスとして定義することで、この場合、メンバ変数に情報を保存しておけます。また、これに合わせて、operator<< のオーバーロードを用意します。

#include <iostream>

namespace {

    class myformat {

        template <typename T, typename Traits>
        friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream<T, Traits>& os, const myformat& fmt);

    public:
        myformat(int width) :
            mWidth(width)
        {}

    private:
        int mWidth;
    };

    template <typename T, typename Traits>
    std::basic_ostream<T, Traits>& operator<<(std::basic_ostream<T, Traits>& os, const myformat& fmt)
    {
        os.width(fmt.mWidth);
        os.setf(std::ios::right, std::ios::adjustfield);
        return os;
    }

}

int main()
{
    std::cout << "xyz" << std::endl;
    std::cout << myformat(5) << "xyz" << std::endl;
    std::cout << myformat(10) << "xyz" << std::endl;
}

実行結果:

xyz
  xyz
       xyz

問題③

問題③ myformatマニピュレータは、フィールドの幅をテンプレート実引数で指定する形にすると、動的な変更はできなくなりますが、より単純に実装できます。以下のように使用できる myformatマニピュレータを作成してください。

std::cout << myformat<10> << "xyz" << std::endl;


フィールドの幅の指定を行う場所が、関数の実引数で無くなったため、標準の operator<< が機能できます。

#include <iostream>

namespace {
    template <int WIDTH, typename T, typename Traits>
    std::basic_ostream<T, Traits>& myformat(std::basic_ostream<T, Traits>& os)
    {
        os.width(WIDTH);
        os.setf(std::ios::right, std::ios::adjustfield);
        return os;
    }
}

int main()
{
    std::cout << "xyz" << std::endl;
    std::cout << myformat<5> << "xyz" << std::endl;
    std::cout << myformat<10> << "xyz" << std::endl;
}

実行結果:

xyz
  xyz
       xyz


参考リンク


更新履歴

’2017/2/10 新規作成。



第30章のメインページへ

C++編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る