2016-12-20 4 views
0

Rubyのようないくつかの言語では、フォーマットされた出力 を「ワンライナー」として作成するための派手な構文があります。`std :: ostringstream`が` std :: ostringstream& `を返す` operator << `を持っていたらどうなりますか?

これは、一部のC++アプリケーションでも一般的に必要です。

:彼らはこのような何かを書くことができるようにするため

struct string_formatter { 
    std::ostringstream ss; 

    template <typename T> 
    string_formatter & operator << (const T & t) { 
    ss << t; 
    return *this; 
    } 

    operator std::string() const { 
    return ss.str(); 
    } 
}; 

:ここではいくつかのサンプルコードです:

if (num_doggies > num_biscuits) { 
    std::ostringstream ss; 
    ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!"; 
    log_warn(ss.str()); 
    this->negotiate_biscuit_reduction(); 
} 

いくつかのオープンソースC++ 98件のプロジェクトは、このようになります回避策を持っています

if (num_doggies > num_biscuits) { 
    log_warn(string_formatter{} << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!"); 
    this->negotiate_biscuit_reduction(); 
} 

3行を1行に変換します。

しかし、string_formatterクラスは、この暗黙の変換の主な理由で、コードレビューの観点からかなり悪いです。 暗黙のコンバージョンは通常 と思われ、共通タイプまたはプリミティブタイプに変換するときにはより悪いです intまたはstd::stringのようになります。 C++ 11では

我々はわずかに変更することができ:string_formatterはR値の基準である場合

operator std::string() && { 
    return ss.str(); 
    } 

今変換のみトリガされます。 したがって、トリガーする可能性は低くなりますが、さらに複雑になります。それは実際に悪くないですか? 議論の余地があります。

も言及する価値:他の人はこれがstring_formatterシムなし を動作させるためにさらにより精巧なハック行っている:ここhttps://codereview.stackexchange.com/questions/6094/a-version-of-operator-that-returns-ostringstream-instead-of-ostream

ません暗黙の型変換を、私たちは通常、標準ライブラリのタイプに演算子をオーバーロードしていますいいえ。


少しバックアップしましょう。なぜ私は妥協してこれを行うことができないのですか?それは、少なくとも、もう少しコンパクトだ:

if (num_doggies > num_biscuits) { 
    std::ostringstream ss; 
    log_warn((ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!").str()); 
    this->negotiate_biscuit_reduction(); 
} 

ためstd::ostringstream::operator <<戻りstd::ostream &なく std::ostringstream &それは、これはコンパイルできないことが判明します。 <<が解決されるまでには、を使用できないため、ostream &しかありません。

私の質問は、なぜその場合ですか?

なぜですかstd::ostringstream::operator <<返信std::ostringstream &?それは次のとおりです。技術的または安全上の理由から

  • 望ましくない
  • レガシー標準ライブラリの実装者のための不必要な難易度を追加する - それは、常にこの方法だったと、今、それを変更するコードを壊すかもしれません。 (しかし、正確にどのようなコードがこれによって壊れてしまうのでしょうか?std::ostringstream &は継承関係のために標準変換によってstd::ostream &に変換される可能性があります)。
  • あくまでも参考にしてください。

注:私はstring_formatterとロガークラスを設計するさまざまな方法をよく知っています。私は具体的には、std::ostringstreamstd::ostream &を返すほうがずっと良い標準ライブラリに設計上の理由があるかどうかに関心があります。

+0

あなたは自明なし、string_formatter' 'に'の.strを() '追加することができますか? –

+0

@ T.C。うん、それは本当にポイントではない、なぜ私はなぜ 'std :: ostringstream'が' std :: ostream& 'を返す必要があるのか​​分からない理由があるなら、もっと興味があります –

+0

ostringstreamに演算子がないので?それは、基本的なostream oneを継承の魔法によって使います。 –

答えて

0

警告メッセージのログを処理するコードを単純化できる場合は、operato<<関数が返すものに気をつけるかどうかは、あなたの投稿からは分かりません。

警告メッセージを記録するコードを簡略化する方法の1つです。あなたのケースでは

#include <iostream> 
#include <sstream> 
#include <string> 

void log_warn(std::string const& s) 
{ 
    std::cout << s; 
} 

struct log_warning_impl 
{ 
    mutable std::ostringstream ss; 

    ~log_warning_impl() 
    { 
    log_warn(ss.str()); 
    } 
}; 

template <typename T> 
log_warning_impl const& operator<<(log_warning_impl const& l, const T & t) 
{ 
    l.ss << t; 
    return l; 
} 

log_warning_impl const& operator<<(log_warning_impl const& l, std::ostream&(*f)(std::ostream&)) 
{ 
    l.ss << f; 
    return l; 
} 


#define WARNING_LOGGER log_warning_impl{} 

int main() 
{ 
    WARNING_LOGGER << "There is a problem in the " << 10 << "-th line of the data file" << std::endl; 
} 

、あなたは簡単に使用することができます。

if (num_doggies > num_biscuits) 
{ 
    WARNING_LOGGER << "There are " << num_doggies << " puppy dogs and only " << num_biscuits << " biscuits!"; 
} 
関連する問題