constメンバー変数とvectorの問題
@chikashimiyamaさんの記事に対してコメントした妥協案より良さそうな実装を思いついたので、メモしておく。
コメントした妥協案の最大の不満点は、
- コンストラクター、代入演算子の実装が面倒臭い
ことである。これは、結局コピー/ムーブできないconstメンバー変数を抱えているからだ。
そこで、メンバー変数をクラスの外に出し、書き込みできないように関数経由で読み取るようにしてみる。
#include <vector>
#include <iostream>
template <class T>
class AutoROData
{
T m_data;
public:
explicit AutoROData(const T &data)
: m_data{data}
{}
const T &operator()() const {
return m_data;
}
};
class WithConst
{
public:
WithConst(const int value1, const int value2)
: value1{value1}
, value2{value2}
{}
int getConstValue1() const {
return value1();
}
void setConstValue1(const int value1) {
// this->value1 = value1; // 間違って書き換えようとしても、コンパイルエラーになる
}
int getValue2() const {
return value2;
}
void setValue2(const int value2) {
this->value2 = value2;
}
protected:
AutoROData<int> value1;
int value2;
};
int main()
{
std::vector<WithConst> vec{
{20,21},
{30,31},
{40,41}
};
vec.erase(vec.begin()+1);
for ( const auto &v : vec ) {
std::cout << v.getConstValue1() << "," << v.getValue2() << '\n';
}
}
データ用クラスを一々実装するのも面倒臭い1のでテンプレートにしている。
AutoROData<T>
型のオブジェクトは、コピー/ムーブできるようにするために代入演算子を削除していないが、元の型(T型)ではなくAutoROData<T>
型のオブジェクトを代入する必要があるので、間違って代入してしまうことはないだろう。
これで、WithConst
クラス自体はコピー/ムーブできるが、メンバー変数value1
は読み取り専用(に見えるよう)になった。
おまけ
メンバー変数value1
から元のint型の値を読み取るためには関数形式value1()
で呼び出す必要があるので、多少違和感がある。
そこで、C++標準委員会に提出された「C++ Properties -- a Library Solution」を参考にプロパティ化すると、自然に見えるようになる。
#include <vector>
#include <iostream>
template <class T>
class AutoROProperty
{
T m_data;
public:
explicit AutoROProperty(const T &data)
: m_data{data}
{}
operator const T &() const {
return m_data;
}
};
class WithConst
{
public:
WithConst(const int value1, const int value2)
: value1{value1}
, value2{value2}
{}
int getConstValue1() const {
// return value1();
return value1; // 元のint型の値を読み取る場合と全く同じように書ける
}
void setConstValue1(const int value1) {
// this->value1 = value1; // 間違って書き換えようとしても、コンパイルエラーになる
}
int getValue2() const {
return value2;
}
void setValue2(const int value2) {
this->value2 = value2;
}
protected:
// AutoROData<int> value1;
AutoROProperty<int> value1;
int value2;
};
int main()
{
std::vector<WithConst> vec{
{20,21},
{30,31},
{40,41}
};
vec.erase(vec.begin()+1);
for ( const auto &v : vec ) {
std::cout << v.getConstValue1() << "," << v.getValue2() << '\n';
}
}
-
プログラマーは面倒臭がり屋である(^^; ↩