ポリシーベースの設計に関する記事を読み、自分で何かを試してみたいと思った後、以前行ったロガークラスをポリシーベースのアプローチに再設計することに時間を費やしています。
いくつかのコード:
template <class Filter, class Formatter, class Outputter>
class LoggerImpl : public LoggerBase {
public:
LoggerImpl(const Filter& filter = Filter(), const Formatter& formatter = Formatter(), const Outputter& outputter = Outputter());
~LoggerImpl();
void log(int channel, int loglevel, const char* msg, va_list list) const;
private:
const Filter mFilter;
const Formatter mFormatter;
const Outputter mOutputter;
};
template <class Filter, class Formatter, class Outputter>
LoggerImpl<Filter, Formatter, Outputter>::LoggerImpl(const Filter& filter, const Formatter& formatter, const Outputter& outputter) :
mFilter(filter), mFormatter(formatter), mOutputter(outputter) {
debuglib::logdispatch::LoggerMgr.addLogger(this);
}
typedef LoggerImpl<NoFilter, SimpleFormatter, ConsoleOutputter> ConsoleLogger;
typedef LoggerImpl<ChannelFilter, SimpleFormatter, VSOutputter> SimpleChannelVSLogger;
typedef LoggerImpl<NoFilter, SimpleFormatter, FileOutputter> FileLogger;
ConsoleLogger c;
SimpleChannelVSLogger a(const ChannelFilter(1));
FileLogger f(NoFilter(), SimpleFormatter(), FileOutputter("log.txt"));
// macro for sending log message to all current created loggers
LOG(1, WARN, "Test %d", 1423);
ロガーによっては、SimpleChannelVsLogger 内のログチャネルや FileOututter 内のログファイルのファイル名などの追加情報を渡す必要があります。
パラメーターを LoggerImpl のコンストラクターに const 参照として渡し、後でロガー クラスに格納されているオブジェクトにコピーします。一時的に作成されたオブジェクトを const 参照にバインドするときに発生する関数引数を介して有効期間の延長が推移的ではないため、それらをコピーする必要があります (詳細はこちら: Does a const reference prolong the life of a temporary? )。
ここで最初に: テンプレートを使用するときにランタイム割り当てに興味がないのでポインターを使用したくない場合は、一時的に作成されたオブジェクトを上記のようにコピーする以外に解決策はないと思いますか?
コピーの実際の問題は、FileOutputter に付属しています。もちろん、ストリームをコピーすることはできません。ストリームを含む FileOutputter オブジェクトをコピーするにはどうすればよいでしょうか。この問題を克服するために、次の解決策を思い付きました。
struct FileOutputter {
// c_tor
FileOutputter() {}
// c_tor
explicit FileOutputter(const char* fname) {
mStream = std::make_shared<std::fstream>(fname, std::fstream::out);
}
// The copy c_tor will be invoked while creating any logger with FileOutputter
// FileLogger f(NoFilter(), SimpleFormatter(), FileOutputter("log.txt"));
// as all incoming paramters from the constructors stack frame are copied into the current instance of the logger
// as copying a file-stream is not permitted and not good under any means
// a shared pointer is used in the copy c_tor
// to keep the original stream until no reference is referring to it anymore
FileOutputter(const FileOutputter& other) {
mStream = other.mStream;
}
~FileOutputter() {
}
void out(const char* msg) const {
*mStream << msg;
}
std::shared_ptr<std::fstream> mStream;
};
どういうわけか、これは「単純なロガークラス」にとっては少し複雑に思えるかもしれませんが、これは、この場合のポリシーベースの設計アプローチの「問題」にすぎない可能性があります。
どんな考えでも大歓迎です