状況がよくわかりませんが、プロキシが必要なようです。
class LogSingleton
{
public:
LogSingleton& instance() { /* ... */ }
void lock(); // lock mutex
void unlock(); // unlock mutex
template <typename T>
friend LogSingleton& operator<<(LogSingleton& pLog, const T& pX)
{
// needs to be locked first
assert(is_locked());
/* output pX however */
return pLog;
}
};
class LogProxy
{
public:
LogProxy()
{
// manage lock in proxy
LogSingleton::instance().lock();
}
~LogProxy()
{
LogSingleton::instance().unlock();
}
};
// forward input into the proxy to the log, knowing it's locked
template <typename T>
LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
LogSingleton::instance() << pX;
return pProxy;
}
// now expose proxy
typedef LogProxy log;
そして、あなたはこれをするでしょう:
log() << "its locked now" << "and the temporary will die" << "here ->";
ロックはコンストラクタとデストラクタで行われ、最後にデストラクタが呼び出されます。
Tony が正しく指摘しているように、これはロックを不必要に長く保持します。ロックは、への「最終」出力にのみ必要ですLogSingleton
。これを想像してください:
log() << "this next function takes 5 minutes"
<< my_utterly_crappy_function() << "ouch";
何もログに記録されていませんが、mutex は長時間ロックされています。出力をバッファリングしてから、一度にすべて出力することをお勧めします。
class LogProxy
{
public:
~LogProxy()
{
// manage lock in proxy
LogSingleton::instance().lock();
// no-throw, or wrap mutex use in a scoped-lock
LogSingleton::instance() << mBuffer.rdbuf();
LogSingleton::instance().unlock();
}
// buffer output
template <typename T>
friend LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
mBuffer << pX;
return pProxy;
}
private:
std::ostringstream mBuffer;
};
バッファが出力可能になるまで、ロックは取得されません。