ライブラリが提供する他のものを使用する前に、ユーザーが呼び出す必要がある初期化用の個別のインターフェイスをエクスポートするライブラリを検討してください。このステップでは、特定のシステム状態が照会され、対応する変数に格納されます。これは定数にマップすることはできませんが、外部ソースからの書き込みによる変更を受けやすいものであってはなりません。つまり、システム状態は異なる翻訳単位でクエリ可能であるべきですが、書き込み可能であってはなりません。
わかりやすい例の 1 つは、システムの起動をマークするタイムスタンプです。これはコンパイル時の定数にすることはできませんが、書き込み可能にすることもできません。
これは、静的関数のみを実装し、プライベートな静的メンバーを使用するクラスで実現できます。
// system.h
#include <chrono>
using sys_time_point = std::chrono::system_clock::time_point;
class System
{
public:
System () = delete;
// possibly other deleted functions
static bool init () noexcept;
static bool ready () noexcept;
static const sys_time_point& initTime() noexcept;
private:
static bool initState_;
static sys_time_point initTime_;
};
// system.cpp
bool System::initState_ = false;
sys_time_point System::initTime_ = std::chrono::system_clock::now();
問題は、関数が相互に依存している可能性がありますが、ユーザー定義型のプライベート状態を変更またはアクセスするのではなく、システム状態を照会するためのさまざまな機能を多かれ少なかれ定義しているため、後者のアプローチは不適切な設計選択であると考えています。
私はむしろ2番目のアプローチに行きたいです。namespace System
前のクラスと同じ機能をグループ化する aを想定します。
// System.h
#include <chrono>
namespace System
{
using sys_time_point = std::chrono::system_clock::time_point;
bool init () noexcept; // needs to be called
bool ready () noexcept; // can be used by other lib components and lib clients
const sys_time_point& initTime() noexcept; // returns system startup time point
// other stuff here ...
}
// System.cpp
namespace System
{
namespace
{
bool sysInitState = false;
sys_time_point sysInitTime = std::chrono::system_clock::now();
}
bool init() noexcept
{
// init code here ... set and return sysInitState accordingly
}
bool ready() noexcept
{
return sysInitState;
}
const sys_time_point& initTime() noexcept
{
return sysInitTime;
}
}
名前のない名前空間を使用して、他の翻訳単位の変数への外部リンクを抑制します。私の知る限り、の関数を使用する以外に、他の翻訳単位でそれらにアクセスする方法はありませんnamespace System
。const_cast<>
また、const refs または return by value が原因で、書き込みもできません。ただし、邪悪なプログラマーがconst refs を非 const refs に変更する可能性があるシナリオは除きます。
私の質問は次のようになります。
- 上記の2番目の解決策はまったく正しいですか?
- 上記の2番目の解決策は実行可能ですか?
- より安全で実装しやすい他のソリューションはありますか?
みんな、ありがとう!