プロパティの実装:今ならこうする(?)
型Tのプロパティは、
- get: 引数なしで、Tを返す
- set: const T&を引数とし、Tを返す
の2つの関数オブジェクトを持ち、それぞれ利用者にあらかじめセットしてもらうことにします。標準C++ライブラリが提供するクラステンプレート: std::function<> を用いて:
std::function<T()> get; std::function<T(const T&)> set;
をprivateメンバに持たせることにしましょう。std::function<>には、テンプレート引数に与えたシグニチャ(引数と戻り値)が一致するなら 関数ポインタ/ラムダ式/ファンクタ(operator()を持つクラス)を問わずセットでき、呼び出すことができます。
#include <iostream>
#include <functional>
int global_value;
struct get_functor {
int operator()() const {
return global_value;
}
};
int set_function(const int& value) {
return global_value = value;
}
int main() {
std::function<int(const int&)> set;
std::function<int()> get;
// function
set = &set_function;
set(123);
std::cout << global_value << std::endl;
// lambda
get = []() { return global_value; };
std::cout << get() << std::endl;
// functor
get = get_functor();
std::cout << get() << std::endl;
}
また、thisをキャプチャしたラムダ式を与えることでクラスのメンバにもアクセスできます。
#include <iostream>
#include <functional>
class foo {
private:
int member_value;
int set_member(const int& value) { return member_value = value; }
public:
// コンストラクタで get/set を設定する
foo() {
// thisをキャプチャしたlambda式を与える
get = [this]() { return member_value; };
set = [this](const int& value) { return set_member(value); };
}
std::function<int()> get;
std::function<int(const int&)> set;
};
int main() {
foo f;
f.set(123);
std::cout << f.get() << std::endl;
}
std::function<>を使えばプロパティを実装できそうです。ほとんどナカミがありませんけど...
#include <functional>
template<class T>
class property {
public:
void operator()(const std::function<T()>& getter, const std::function<T(const T&)>& setter) {
// 一度しかセットできないようにしました
if ( !get ) get = getter;
if ( !set ) set = setter;
}
T operator()() const { return get(); }
T operator()(T const& value) { return set(value); }
operator T() const { return get(); }
T operator=(T const& value) { return set(value); }
typedef T value_type;
private:
std::function<T()> get;
std::function<T(const T&)> set;
};
