2017-07-22 13 views
2

私は自分のログクラスを改造しようとしています。しかし、私は問題に直面しています。
私はユーザーに、このインターフェイスを公開する:決定的な破壊に頼って、復帰時の破壊を避ける

mylog() << "hello"; 

アイデアはmylogが定義されたログタイプのためにいくつかの有用な特性を定義するLoggerのインスタンスであることです。そのoperator()関数は、タイプLogStreamのインスタンスを返します。しかし、最後に改行文字を自動的に出力したいので、LogStreamのデストラクタでそれを行う考えがありました。

私の現在の実装では、この(LogStreamLoggerが大幅にダウン易しく書き直されている)のようになります。Interstingly

#include <iostream> 

struct LogStream 
{ 
    ~LogStream() { std::cout << '\n'; } 

    template<class T> 
    LogStream& operator<<(const T& t) 
    { 
     std::cout << t; 
     return *this; 
    } 
}; 

struct Logger 
{ 
    LogStream operator()() 
    { 
     return LogStream{} << "message: "; 
    } 
}; 

int main() 
{ 
    Logger log; 
    log() << "hello!"; 
} 

、私は私の以前の実装は、RVOに依存したコードのこの作品を考え出しました。コンパイラは常にコピー・エリジョンを実行していたので、デストラクタは必要な方法で動作しました。ただし、このコードでは、コピーが発生したときにコピーコンストラクタが呼び出されているため、改行文字は2回出力されています(operator())。
問題は、私は一時的なインスタンスを返し、代わりにoperator()の体でこれを入れないと消え:

LogStream stream; 
stream << "message: "; 
return stream; 

今RVOが、それは私が望むように動作します。
私は後で= deleteコピーコンストラクタを作成しました。なぜなら、とにかくそれが意味を成し、効果的にコードをコンパイルできないからです。

RVOに依存するハッピーソリューションを使用せずに、私が望むインターフェイスを提供するためのオプションは何ですか?

+4

デストラクタで改行を出力する必要があるかどうかを示すために 'LogStream'の中にフラグを追加し、移動したときにこのフラグをfalseに設定します。 – Holt

+0

それはうまくいくでしょうし、おそらく最も簡単な解決策かもしれませんが、私はそれを好きではありません。私はむしろコピーコンストラクタを削除したままにしておきます。 – Asu

+0

@Asu、Holtの提案を使用することができない場合は、RVOが "可能かもしれない"(コードスニペットのような特定のコンテキストで)ではないC++ 17標準でコンパイルする必要があるかもしれません。 – WhiZTiM

答えて

2

LogStreamにコンストラクタを追加すると、char const *になります。

LogStream(char const* c) { std::cout << c; } 

その後、代わりにoperator()内の一時LogStreamを作成するのではなく、戻り値自体を初期化するために、リストの初期化を使用します。

LogStream operator()() 
{ 
    return {"message: "}; 
} 

一時的な改行は、余分な改行とともに回避されます。

Live demo-fno-elide-constructorsを使用してもコピーエリーションを無効にしても、改行が追加されないことに注意してください)。

関連する問題