Properties (SC22/WG21/N1615)

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 ライセンスで提供されます。

The MIT License (MIT)

  Copyright 2012-2022 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 


参考

 


 

変更履歴

2022-05-17 - 表示スタイルなど更新
2012-12-31 - 新規作成

 

Programming Items トップページ

プライバシーポリシー