SC22/WG21/N1615 で提案された C++ でプロパティを実現するテンプレートの紹介です。
標準としては否認されたようですが、場面によっては有効な手法と思います。
| コンパイラ : | Visual Studio 2012 | |
| OS : | Windows8 64bit 日本語版 | |
まずテンプレートライブラリにあたる ”property.h” です。オリジナルから私の独断で冗長な部分を削ったものを以下に記載します。
[property.h]
//
// [参照文書]
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1615.pdf
//
#ifndef HIDETOSHI_PROPERTY
#define HIDETOSHI_PROPERTY
#include <map>
namespace hidetoshi {
// a read-write property with data store and
// automatically generated get/set functions.
// this is what C++/CLI calls a trivial scalar property
template <class T>
class Property
{
private:
protected:
T data_;
public:
// access with function call syntax
Property() : data_(T()) {
}
// access with '=' sign
// in an industrial-strength library,
// specializations for appropriate types might choose to
// add combined operators like +=, etc.
virtual operator T() const
{
return data_;
}
virtual T operator = ( T const & value )
{
data_ = value;
return data_;
}
typedef T value_type; // might be useful for template deductions
};
// a read-only property calling a user-defined getter
template <class T, class Object, typename T (Object::*real_getter)()>
class ROProperty
{
private:
Object * my_object;
public:
// Constructor
ROProperty() : my_object(nullptr)
{
}
// this function must be called by the containing class, normally in a
// constructor, to initialize the ROProperty so it knows where its
// real implementation code can be found. obj is usually the containing
// class, but need not be; it could be a special implementation object.
void operator () ( Object * obj )
{
my_object = obj;
}
void set( T const & value ); // reserved but not implemented, per C++/CLI
// use on rhs of '='
operator T() const
{
if ( my_object == nullptr ){
throw std::logic_error("ERROR: Invalid use of the class ROProperty, my_object is not initialized.");
}
return (my_object->*real_getter)();
}
typedef T value_type; // might be useful for template deductions
};
// a write-only property calling a user-defined setter
template < class T, class Object, typename T (Object::*real_setter)( T const & ) >
class WOProperty
{
private:
Object * my_object;
public:
// Constructor
WOProperty() : my_object(nullptr)
{
}
// this function must be called by the containing class, normally in
// a constructor, to initialize the WOProperty so it knows where its
// real implementation code can be found
void operator () ( Object * obj )
{
my_object = obj;
}
// access with '=' sign
T operator = ( T const & value )
{
if ( my_object == nullptr ){
throw std::logic_error("ERROR: Invalid use of the class WOProperty, my_object is not initialized.");
}
return (my_object->*real_setter)( value );
}
typedef T value_type; // might be useful for template deductions
};
// a read-write property which invokes user-defined functions
template < class T, class Object, typename T (Object::*real_getter)(), typename T (Object::*real_setter)( T const & ) >
class RWProperty
{
private:
Object * my_object;
public:
// this function must be called by the containing class, normally in a
// constructor, to initialize the ROProperty so it knows where its
// real implementation code can be found
void operator () ( Object * obj )
{
my_object = obj;
}
// access with '=' sign
operator T() const
{
return (my_object->*real_getter)();
}
T operator = ( T const & value )
{
return (my_object->*real_setter)( value );
}
typedef T value_type; // might be useful for template deductions
};
} // namespace hidetoshi
#endif // HIDETOSHI_PROPERTY
次に上記のテンプレートライブラリを使用する法のサンプルです。
[PropetyOnCpp.cpp]
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include "property.h"
using namespace std;
using namespace hidetoshi;
template <class T>
class IDProperty : public Property<T>
{
private:
public:
IDProperty()
{
}
virtual operator T() const
{
return data_;
}
virtual T operator = ( T const & value )
{
data_ = value;
return data_;
}
};
class myClass {
private:
// for RO
int numKids_ ;
int get_numKids()
{
return numKids_;
}
// for WO
float weight_;
float set_Weight( float const & value )
{
weight_ = value ;
return value;
}
// for RW
std::string secretkey_;
std::string set_Secretkey( const std::string& key )
{
return (secretkey_ = key);
}
std::string get_Secretkey()
{
return secretkey_;
}
public:
// Name and ID are read-write properties with automatic data store
Property<std::string> Name ;
IDProperty<long> ID ;
// Number_of_children is a read-only property
ROProperty< int, myClass, &myClass::get_numKids > NumberOfChildren;
// WeightedValue is a write-only property
WOProperty< float, myClass, &myClass::set_Weight > WeightedValue;
// Secretkey is a read-write property calling user-defined functions
RWProperty< std::string, myClass, &myClass::get_Secretkey, &myClass::set_Secretkey > Secretkey;
// constructor for this myClass object must notify member properties
// what object they belong to
myClass()
: numKids_(24), weight_(60), secretkey_("This is a initial secret key.")
{
NumberOfChildren( this );
WeightedValue( this );
Secretkey( this );
}
};
int _tmain(int argc, _TCHAR* argv[])
{
/*========*/
/* 前処理 */
/*========*/
/*========*/
/* 処理部 */
/*========*/
{
myClass thing;
// Property<> members:
{
thing.Name = "Pinkie Platypus";
string s1 = thing.Name;
cout << "Name = " << s1 << endl;
thing.ID = 12345678;
long id = thing.ID;
cout << "ID = " << id << endl;
cout << endl;
}
// ROProperty<> member
{
int brats ;
brats = thing.NumberOfChildren;
cout << "Children = " << brats << endl;
cout << endl;
}
// WOProperty<> member
{
thing.WeightedValue = 1.618034f;
cout << endl;
}
// RWProperty<> member
{
std::string key;
thing.Secretkey = "?????";
key = thing.Secretkey;
cout << "Secretkey = " << key << endl;
cout << endl;
}
}
/*========*/
/* 後処理 */
/*========*/
{
string str ;
cout << "HIT [Enter] KEY !! " ;
getline( cin, str );
}
return EXIT_SUCCESS;
}
本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。
| 2022-05-17 | - | 表示スタイルなど更新 |
| 2012-12-31 | - | 新規作成 |