4

コンソールへの出力で使用する色のストリーム マニピュレータを作成しようとしています。テキストと背景の色を変更して機能します。

std::cout << ConColor::Color::FgBlue << 123 << "abc"; //text is blue, sticky

問題は署名にあります:

std::ostream &FgBlue(std::ostream &);

このシグネチャは、派生クラスなども許可しますstd::ostringstreamが、文字列ストリームの色を変更する方法はありません。この関数は、そのような引数で呼び出されたかどうかに関係なく、コンソールの色を変更します。

std::coutしたがって、引数が、などの行に沿ったものであることを確認したいと思います。将来の標準でさらにオブジェクトが追加されるstd::wcout場合に備えて、一般的なものにしたいと思います。std::ostream

std::is_sameandを含む多くのことを試しましstd::is_base_ofたが、前者が機能しない場合、から継承する引数の型std::basic_ostream<>は関数に渡されたときに比較している型にキャストされ、誤検知を与えるため、最終的には無意味であることに気付きました。

これにより、最終的に以下の回答にたどり着きました (可変個のテンプレートのテンプレート引数? うわー、それは一口です!) ただし、いくつかの問題があります。

  • コンパイラは可変個引数テンプレートをサポートする必要があります。MSVCでのソリューション作業を希望します。
  • std::ostringstreamコンパイラは、異なる数のテンプレート引数 ( 2 ではなく 3 を持つ など) を持つ派生クラスが使用される場合、関数シグネチャを通過しないため、不可解なエラーを出します。
  • たとえば、stdout をファイルにリダイレクトすることは可能です。そのため、引数がstd::coutであっても、stringstream の場合と同じことが起こります。

他のソリューションを投稿することをお勧めします。できれば私のものよりも優れていることを願っています。少なくとも VS11 で動作するものを投稿してください。

4

2 に答える 2

1

std::basic_ostreamインスタンス化を検出するための特性は次のとおりです。

template<typename T> struct is_basic_ostream {
  template<typename U, typename V>
  static char (&impl(std::basic_ostream<U, V> *))[
    std::is_same<T, std::basic_ostream<U, V>>::value ? 2 : 1];
  static char impl(...);
  static constexpr bool value = sizeof(impl((T *)0)) == 2;
};

使用:

template<typename T>
void foo(T &) {
  static_assert(is_basic_ostream<T>::value,
    "Argument must be of type std::basic_ostream<T, U>.");
}

テンプレート引数演繹法を使用して、(非適切な)basic_ostream基本クラスのテンプレート パラメーターを推論します (存在する場合)。より一般的な解決策として、とを単一の可変引数パラメーターに置き換えるUと、可変引数テンプレート パラメーターをサポートするコンパイラーでジェネリック トレイトを記述できるようになります。Vis_instantiation_of


stdout がファイルにパイプされているかどうかを検出するには (もちろん、実行時にのみ検出できます)、isatty;を使用します。cout で isatty() を使用する方法を参照してください。または、cout == ファイル記述子 1 と仮定できますか?

于 2012-11-01T09:21:00.640 に答える
1

いろいろ試行錯誤した結果、以下のようになりました。

template<template<typename...> class T, typename... U>
void foo(T<U...> &os) {
    static_assert(
        std::is_same<
            std::basic_ostream<U...>, 
            typename std::remove_reference<decltype(os)>::type
        >::value, 
        "Argument must be of type std::basic_ostream<T, U>."
    );
    //...
}

以下の各テストを含むソース コードは、ここにあります
タイプを、より明示的で自由度の高い類似の自作タイプ (例: インスタンス化) に置き換えたソース コードは、ここで見つけることができます。

  • 渡すstd::coutと、std::wcout正常にコンパイルされます。
  • のインスタンスを渡すと、std::ostringstreamテンプレート引数の数について文句を言うようになります。
  • std::fstream同じ数のテンプレート パラメータを持つ のインスタンスを渡すと、静的アサーションが失敗します。
  • 自作の 2 パラメータ テンプレート クラスを渡すと、静的アサーションが失敗します。

できる限りこれを改善してください。

于 2012-11-01T07:19:39.490 に答える