Readonly
この記事は私以外にはReadonlyです。
C#にはreadonly
という修飾子がありまして…
class Test
{
public const int value_c = 10;
public readonly int value_r = 20;
public Test(){
value_r = 10;
}
public Test(int v)
{
value_r = v;
}
}
このように、readonly
はconst
の機能である宣言時に初期化に加え、コンストラクタ内での初期化も許可されています。その他の点はconstと同様です。
C++での実装
というわけでゴリゴリ書きました。
C++にはfriend
というアクセスを許可する修飾子がありまして…
それで、パパパっと親クラスのコンストラクタのみ許可して、終わりっ!
template <class Parent,class T>
class ReadOnly {
public:
typedef T value_type;
friend Parent::Parent();
private:
T instance;
value_type& operator=(const value_type& v) {
instance = v;
return instance;
}
public:
//constructor
ReadOnly() {}
ReadOnly(const T& v) : instance(v){}
};
「このコードは実行できませんのでご注意を」
まずは代入ができるか確認して、できたら暗黙キャストでも入れよう。
テストクラスはこんな感じ
class test{
public:
ReadOnly<test,int> read;
test(){
read = 10;
}
};
問題
friend Parent::Parent();
にて
error: C++ requires a type specifier for all declarations
前方宣言によって使用できるのは型の宣言のみで内部実装は見えない。
コンストラクタを実装していない可能性もあり得る。よってtestクラスを先に書く必要がある。
他にもいろいろと問題点はあるが、実装依存のデータ構造はいろいろと破綻しているので、実装しない。別にファイル分割が面倒くさいとか、Macにしてからvimrcの調子が悪いとか、そういうことではない。
まとめ
この問題を解決するのはわりと難しそうだ。
SFINAEでなんとかと思ったが、そもそも#include前に定義しないと全部スコープ外になるし、今回はそういう問題じゃない。
今日はもう無理…
メモ
・friendは、定義されてない型や関数にすることは可能
・スコープ解決演算子(::)の左辺は必ず存在しないとダメ
・前方宣言は、メンバの定義は参照できない
・コンストラクタのオーバーロード全てに対応できるのか?
・よってコンストラクタのfriendは、Readonlyクラスより先に定義されている必要がある。
・このままではデータ構造としては非常に使い難いものになってしまう。