始めに
C# に慣れちゃうと C++ にもプロパティーが欲しくなる事があり検索するとプロキシとして動くオブジェクトを作る実装例が見受けれます。 軽く眺める限りコード量に見合うメリットが感じられ無いので出来る限り簡潔に書ける方法を考えてみました。
実例
#include <cstddef>
#include <cstdint>
#include <iostream>
struct Foo {
int one = 1;
union { // size = 1
char pad;
struct {
auto operator=(int n) -> const int& { // setter
auto this_ = reinterpret_cast<Foo*>(std::intptr_t(this) - offsetof(Foo, pad));
return this_->one = n;
}
operator int() const { // getter
auto this_ = reinterpret_cast<Foo*>(std::intptr_t(this) - offsetof(Foo, pad));
return this_->one;
}
char pad;
} value;
};
};
int main() {
Foo f;
f.value = 2;
std::cout << f.value << std::endl;
std::cout << sizeof(f.value) << std::endl;
return 0;
}
無名の union / struct にプロパティーを実現するメソッドを定義し実際の this 位置は offsetof で求めちゃえば、後はやりたい放題でございます。 1バイト必須になりますが char bool int とか組み込み型を一つ union に入れちゃえば良いですし簡単でしょ? 利用者側のコードを変更する事なくフック出来るので無名実装の方がメリットがあります。
無駄な1バイトは char pad[0];
にすると無くなりますが VS はサイズ 0 を含む型の継承を許さないのでコンパイラベンダー依存にしたくない場合は注意して下さい。
実用的なバージョン
業務で実用出来るような気がしてきたので実用的なコードも考えてみました。
/**
* @brief プロパティーの入れ物宣言
* 無名unionに含め位置解決に使用する
*/
#define PROPERTIES() /**/ property<void> property_recognition_
/**
* @brief プロパティー実装の基底
* union に入れる事
*/
template <class Base>
struct property {
using base_type = Base;
// 危険なので抑制 (union 内でのみ作れる)
property() = delete;
property(property&&) = delete;
void operator=(property&&) = delete;
auto operator&() = delete;
/// 本体のポインタを返す
auto base() noexcept -> base_type* {
// g++ -Wno-invalid-offsetof
constexpr auto offset = offset(base_type, property_recognition_);
return reinterpret_cast<base_type*>(std::intptr_t(this) - offset);
}
/// 本体のポインタを返す
auto base() const noexcept -> const base_type* {
const_cast<property*>(this)->base();
}
};
class Foo {
public:
Foo()
{}
union {
PROPERTIES();
struct : property<Foo> {
auto operator=(int n) noexcept -> void {
base()->value_ = n;
}
operator int() const noexcept {
return base()->value_;
}
} value;
};
private:
int value_ = 111;
};
int main() {
Foo t;
return t.value;
}
どでしょ?
operator auto とか operator. の出番なんすかねぇ...
最新は多分こちら https://gist.github.com/m5knt/181e889f2fae995a506f1a8464c1e774
参考
- C++でProperty(getter/setter) https://qiita.com/HogeTatu/items/1bb3a394f88ba90cd37e
- C++でプロパティ https://qiita.com/DandyMania/items/78bb31492bee095bc4b0
- C++でC# みたいなプロパティを使いたい (VS固有) https://qiita.com/hart_edsf/items/aa7d6f01d94405270333
- "Properties" support in C++ https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/n0QcD_K5dBY
- Properties, Methods and Events http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1384.pdf
- C++ Properties -- a Library Solution http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1615.pdf
- Operator Dot (R2) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf
- Operator Dot Wording http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0252r1.pdf
- Smart References through Delegation: An
Alternative to N4477's Operator Dot
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0352r0.pdf