2016-05-01 13 views
0

私はストリーム上でテンプレート化されたクラスStreamContainerを書きたいハンドルを作る:私は、次のクライアントコードと思うだろうストリーム上で、テンプレートクラスは、STDの両方:: coutのとstd :: ofstreamの

#ifndef STREAMCONTAINER_HPP 
#define STREAMCONTAINER_HPP 
#include <string> 
#include <iostream> 
    template<typename Stream> 
    class StreamContainer 
    { 
    public: 
     StreamContainer(std::ostream& os) 
      : m_stream(os) {} 
    private: 
     Stream & m_stream; 
    }; 

#endif 

を作品:

#include "StreamContainer.hpp" 
#include <fstream> 
int main(int argc, char argv[]) 
{ 
    std::ofstream ofs; 
    ofs.open("c:\\code\\temp.txt"); 
    StreamContainer<decltype(std::cout)> coutContainer(std::cout); // C2439 
    StreamContainer<std::ofstream> fileContainer(ofs); // C2664 
} 

は、しかし、それはSTDに合格しようとすると、少なくとものVisual C++ 2015で、動作しません:: coutでは、原因となるエラーC2439(メンバーは初期化できませんでした)とstd :: ofstreamのオブジェクトを渡ししようとしていますエラーC2664が発生します(std :: basic_ofstreamのコンストラクタはstd :: basic_ostreamからconst char *)。私はまた、移動コンストラクタを使用してみましたが、それに他の問題がありました。これを解決する方法に関する提案は非常に高く評価されます。

+1

コンストラクタのパラメータが 'Std :: ostream&'で、Stream& 'ではないのはなぜですか? – interjay

+1

どちらも 'std :: ostream&'に変換できます。なぜそれを使用しないのですか?ここにテンプレートは必要ありません。 –

+0

優秀な質問、@interjay。私がその変更を行うと、問題はなくなります。私は、テンプレート置換(ストリームはstd :: ofstreamにすることができます)を使用して、実行時の置換(std :: ostreamへの参照はstd :: ofstreamへの参照になります)を混乱させていたと思います。 – Alan

答えて

2

この:

StreamContainer(std::ostream& os) 

は次のようになります。

StreamContainer(Stream& os) 

そうでない場合は、あなたのofstreamインスタンス化はostreamos)にofstream&参照(m_stream)を取るしようとしています。もう一方の方向は問題ありませんが、これは基本クラスオブジェクトを派生参照に割り当てています。


あなたは、コンストラクタの引数からクラスのテンプレート引数を推測することはできませんこれはただのファクトリ関数を導入するための良好なユースケースですので:

template <typename Stream> 
StreamContainer<Stream> make_container(Stream& s) { 
    return StreamContainer<Stream>{s}; 
} 

あなたは繰り返す必要はありませんように引数または、より悪いが、decltypeを使用します。

auto coutContainer = make_container(std::cout); 
auto fileContainer = make_container(ofs); 

それとも、本当に、両方がちょうどすることができの場合、型の詳細は必要ありません。