the Visual Studio 2010 have 1 way for build properties, in class's. but isn't a portable code:(
i'm using GNU\GCC\G++.
so don't belive that isn't possible do it in C++;)
so anyone can advice me?

i was testing these code, but i get problems with char* and i can't use th string:(
and seems that i can't use the properties in cin and cout.

#include <iostream>
#include <string>
#include <assert.h>


//property class
#define READ_ONLY 1
#define WRITE_ONLY 2
#define READ_WRITE 3


template <typename Container, typename ValueType, int nPropType>
class property
{
public:
property()
{
  m_cObject = NULL;
  Set = NULL;
  Get = NULL;
}
//-- This to set a pointer to the class that contain the
//   property --
void setContainer(Container* cObject)
{
  m_cObject = cObject;
}
//-- Set the set member function that will change the value --
void setter(void (Container::*pSet)(ValueType value))
{
  if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
    Set = pSet;
  else
    Set = NULL;
}
//-- Set the get member function that will retrieve the value --
void getter(ValueType (Container::*pGet)())
{
  if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
    Get = pGet;
  else
    Get = NULL;
}
//-- Overload the '=' sign to set the value using the set
//   member --
ValueType operator =(const ValueType& value)
{
  assert(m_cObject != NULL);
  assert(Set != NULL);
  (m_cObject->*Set)(value);
  return value;
}
//-- To make possible to cast the property class to the
//   internal type --
operator ValueType()
{
  assert(m_cObject != NULL);
  assert(Get != NULL);
  return (m_cObject->*Get)();
}
private:
  Container* m_cObject;  //-- Pointer to the module that
                         //   contains the property --
  void (Container::*Set)(ValueType value);
                         //-- Pointer to set member function --
  ValueType (Container::*Get)();
                         //-- Pointer to get member function --
};


//testing the property class
class PropTest
{
public:
  PropTest()
  {
    Count.setContainer(this);
    Count.setter(&PropTest::setCount);
    Count.getter(&PropTest::getCount);
    Name.setContainer(this);
    Name.setter(&PropTest::setName);
    Name.getter(&PropTest::getName);
  }
  int getCount()
  {
    return m_nCount;
  }
  void setCount(int nCount)
  {
    m_nCount = nCount;
  }
  property<PropTest,int,READ_WRITE> Count;




  char * getName()
  {
    return m_Name;
  }
  void setName(char  *nCount)
  {
    m_Name = nCount;
  }
  property<PropTest,char *,READ_WRITE> Name;




private:
  int m_nCount;
  char *m_Name;
};


using namespace std;
int main()
{
    PropTest a;
    a.Count=100;
    cin >> a.Name[0];
    cout << a.Name;
    cout << a.Count << endl;
    return 0;
}

true that i'm new with C++. i'm learn it from begining. and i'a a 'baby' with templates.
but anyone tell me something

Recommended Answers

All 17 Replies

The reality is that there are limits to what you can achieve using the combination of implicit conversion operator and the assignment operator. You will not be able to make the "property" look like the actual value (i.e., make a property variable look like a normal variable but have hidden calls to get/set functions).

The main problem is that you can't overload everything, and you can't rely on the implicit conversion to apply everywhere. For example, if you were to have property<PropTest,std::string,READ_WRITE> Name;, then you'd have the following issues:

void Foo(std::string s);

void Bar(std::string& s);

template <typename Something>
void Bla(Something s);

void Bla(std::string s);


int main() {
  PropTest a;

  Foo(a.Name);  // OK, uses implicit conversion.

  Bar(a.Name);  // ERROR, implicit conversion returns a temporary string, which cannot be bound to a non-const reference.

  Bla(a.Name);  // UGH... this will call the template version, not the string version.

  std::cout << a.Name;  // ERROR, will look for a << operator for the property class.

  getline(std::cin, a.Name);  // ERROR, same as Bar().

  a.Name.length();  // ERROR, property does not have a member function named "length".

  // ....

};

The point is, the implicit conversion operator can only really work in a few "easy" situations. You will still need a "get()" function of some kind, very often.

Another important matter is the matter of references. Currently, your property class causes a lot of copying (much of which might be elided, but not all), and if the value-types of your properties are expensive to copy, this is going to be a problem. So, the first thing you could do is update your signatures to use const-references instead:

template <typename Container, 
          typename ValueType, 
          int nPropType>
class property
{
  public:
    typedef void (Container::*SetFuncPtr)(const ValueType& value);
    typedef const ValueType& (Container::*GetFuncPtr)();

    property()
    {
      m_cObject = NULL;
      Set = NULL;
      Get = NULL;
    }
    //-- This to set a pointer to the class that contain the
    //   property --
    void setContainer(Container* cObject)
    {
      m_cObject = cObject;
    }
    //-- Set the set member function that will change the value --
    void setter(SetFuncPtr pSet)
    {
      if((nPropType == WRITE_ONLY) ||
         (nPropType == READ_WRITE))
        Set = pSet;
      else
        Set = NULL;
    }
    //-- Set the get member function that will retrieve the value --
    void getter(GetFuncPtr pGet)
    {
      if((nPropType == READ_ONLY) ||
         (nPropType == READ_WRITE))
        Get = pGet;
      else
        Get = NULL;
    }
    //-- Overload the '=' sign to set the value using the set
    //   member --
    const ValueType& operator =(const ValueType& value)
    {
      assert(m_cObject != NULL);
      assert(Set != NULL);
      assert(Get != NULL);
      (m_cObject->*Set)(value);
      return (m_cObject->*Get)();
    }
    //-- To make possible to cast the property class to the
    //   internal type --
    operator const ValueType&()
    {
      assert(m_cObject != NULL);
      assert(Get != NULL);
      return (m_cObject->*Get)();
    }
  private:
    Container* m_cObject;  //-- Pointer to the module that
                           //   contains the property --
    SetFuncPtr Set; //-- Pointer to set member function --
    GetFuncPtr Get; //-- Pointer to get member function --
};

But as you see, this is all still very tedious, and it might not apply to all situations either (for example, properties that you don't actually store but only deliver on-demand).

I generally find that the best thing to do in that situation is actually to store the value within the property object itself. In cases where you would normally store the value in the container class, this reduces duplication. In cases where you would normally not store the value anywhere (compute it on-demand), this just acts as a "cache" for the value (which you can actually use for some form of optimization, like copy-on-write). And a side benefit is that you can make it a plain value without any efforts. Here is what I mean:

template <typename Container, 
          typename ValueType, 
          int nPropType>
class property
{
  public:
    typedef void (Container::*SetFuncPtr)(const ValueType& value);
    typedef void (Container::*UpdateFuncPtr)(ValueType& value);

    property()
    {
      m_cObject = NULL;
      Set = NULL;
      Update = NULL;
    }
    //-- This to set a pointer to the class that contain the
    //   property --
    void setContainer(Container* cObject)
    {
      m_cObject = cObject;
    }
    //-- Set the set member function that will change the value --
    void setter(SetFuncPtr pSet)
    {
      if((nPropType == WRITE_ONLY) ||
         (nPropType == READ_WRITE))
        Set = pSet;
      else
        Set = NULL;
    }
    //-- Set the get member function that will retrieve the value --
    void getter(UpdateFuncPtr pUpdate)
    {
      if((nPropType == READ_ONLY) ||
         (nPropType == READ_WRITE))
        Update = pUpdate;
      else
        Update = NULL;
    }

    //-- A direct value-get function --
    ValueType& directly_get_value() { 
      return Val; 
    };

    //-- Overload the '=' sign to set the value using the set
    //   member --
    property& operator =(const ValueType& value)
    {
      if((nPropType == WRITE_ONLY) ||
         (nPropType == READ_WRITE)) {
        if( m_cObject && Set )
          (m_cObject->*Set)(value);
        Val = value;
      };
      return *this;
    };
    //-- To make possible to cast the property class to the
    //   internal type --
    const ValueType& get() const {
      if(((nPropType == READ_ONLY) ||
          (nPropType == READ_WRITE)) &&
          ( m_cObject && Update ))
        (m_cObject->*Update)(Val);
      return Val;
    };

    operator const ValueType&() const {
      return this->get();
    };

  private:
    Container* m_cObject;  //-- Pointer to the module that
                           //   contains the property --
    SetFuncPtr Set; //-- Pointer to set member function --
    GetFuncPtr Get; //-- Pointer to get member function --
    mutable ValueType Val; //-- Actual value --
};

The reason I included a directly_get_value is because if the value is stored in the property object, the container class needs some sort of basic function to directly get/set the value if needed.

Another important aspect of this problem is that you know at compile-time whether the property is read-only or read-write (I don't know why you also provide write-only, that doesn't make much sense to me). There is a general principle when working with templates, which is that you shouldn't take compile-time information and check it at run-time (even though the compiler will often optimize the check away). You can do partial specialization of templates in order to provide alternative implementations based on the template argument provided, and that can be very useful because not only do you avoid doing a run-time check for "is it read-only or read-write" but you also cause compilation errors when the property is used incorrectly (and a compile-time error is much better than a run-time error!). So, you can do this:

// this is the read-only version:
template <typename Container, 
          typename ValueType, 
          bool isWritable = false>
class property
{
  public:
    typedef void (Container::*UpdateFuncPtr)(ValueType& value);

    property() : m_cObject(NULL), Update(NULL) { };

    //-- This to set a pointer to the class that contain the
    //   property --
    void setContainer(Container* cObject) {
      m_cObject = cObject;
    };
    //-- Set the get member function that will retrieve the value --
    void getter(UpdateFuncPtr pUpdate) {
      Update = pUpdate;
    };

    //-- A direct value-get function --
    ValueType& directly_get_value() { 
      return Val; 
    };

    //-- To make possible to cast the property class to the
    //   internal type --
    const ValueType& get() const {
      if( m_cObject && Update )
        (m_cObject->*Update)(Val);
      return Val;
    };
    operator const ValueType&() const {
      return this->get();
    };

  private:
    Container* m_cObject;  //-- Pointer to the module that
                           //   contains the property --
    GetFuncPtr Get; //-- Pointer to get member function --
    mutable ValueType Val; //-- Actual value --
};

// this is the read-write version:
// Partial specialization:
template <typename Container, 
          typename ValueType>
class property< Container, ValueType, true >
{
  public:
    typedef void (Container::*SetFuncPtr)(const ValueType& value);
    typedef void (Container::*UpdateFuncPtr)(ValueType& value);

    property() : m_cObject(NULL),
                 Set(NULL), Update(NULL) { };
    //-- This to set a pointer to the class that contain the
    //   property --
    void setContainer(Container* cObject) {
      m_cObject = cObject;
    };
    //-- Set the set member function that will change the value --
    void setter(SetFuncPtr pSet) {
      Set = pSet;
    };
    //-- Set the get member function that will retrieve the value --
    void getter(UpdateFuncPtr pUpdate) {
      Update = pUpdate;
    };

    //-- A direct value-get function --
    ValueType& directly_get_value() { 
      return Val; 
    };

    //-- Overload the '=' sign to set the value using the set
    //   member --
    property& operator =(const ValueType& value)
    {
      if( m_cObject && Set )
        (m_cObject->*Set)(value);
      Val = value;
      return *this;
    };
    //-- To make possible to cast the property class to the
    //   internal type --
    const ValueType& get() const {
      if( m_cObject && Update )
        (m_cObject->*Update)(Val);
      return Val;
    };

    operator const ValueType&() const {
      return this->get();
    };

  private:
    Container* m_cObject;  //-- Pointer to the module that
                           //   contains the property --
    SetFuncPtr Set; //-- Pointer to set member function --
    GetFuncPtr Get; //-- Pointer to get member function --
    mutable ValueType Val; //-- Actual value --
};

As you see, if you have a read-only property, then if the user attempts to write to it (using the assignment operator), it will result in a compilation error, saying that there is no assignment operator for that property type. And this means that you no longer need to perform run-time checks or asserts.

The only remaining sticky point about this is that you have a public-private interface. That is, you have public functions (to set the function pointers or to have direct access to the value), and there isn't really much you can do about that (and befriending won't work). One option is to put those functions into a nested class:

// this is the read-write version:
// Partial specialization:
template <typename Container, 
          typename ValueType>
class property< Container, ValueType, true >
{
  public:
    typedef void (Container::*SetFuncPtr)(const ValueType& value);
    typedef void (Container::*UpdateFuncPtr)(ValueType& value);

    property() : m_cObject(NULL),
                 Set(NULL), Update(NULL) { };

    //-- Overload the '=' sign to set the value using the set
    //   member --
    property& operator =(const ValueType& value)
    {
      if( m_cObject && Set )
        (m_cObject->*Set)(value);
      Val = value;
      return *this;
    };
    //-- To make possible to cast the property class to the
    //   internal type --
    const ValueType& get() const {
      if( m_cObject && Update )
        (m_cObject->*Update)(Val);
      return Val;
    };

    operator const ValueType&() const {
      return this->get();
    };

  private:
    Container* m_cObject;  //-- Pointer to the module that
                           //   contains the property --
    SetFuncPtr Set; //-- Pointer to set member function --
    GetFuncPtr Get; //-- Pointer to get member function --
    mutable ValueType Val; //-- Actual value --

  public:

    struct internals {
      property* p_parent;
      internals(property& aParent) : p_parent(&aParent) { };
      //-- This to set a pointer to the class that contain the
      //   property --
      void setContainer(Container* cObject) {
        p_parent->m_cObject = cObject;
      };
      //-- Set the set member function that will change the value --
      void setter(SetFuncPtr pSet) {
        p_parent->Set = pSet;
      };
      //-- Set the get member function that will retrieve the value --
      void getter(UpdateFuncPtr pUpdate) {
        p_parent->Update = pUpdate;
      };
      //-- A direct value-get function --
      ValueType& directly_get_value() { 
        return p_parent->Val; 
      };
    };
};

Meaning that your PropTest initialization might look like this:

PropTest() {
  property< PropTest, int, READ_WRITE >::internals Count_prop((Count));
  Count_prop.setContainer(this);
  Count_prop.setter(&PropTest::setCount);
  Count_prop.getter(&PropTest::getCount);
  // same for Name..
};

I know that this is probably way more than you asked for, but this is an interesting problem (creating properties), so I wanted to expand on it properly.

i'm sorry do you forget some includes?
i get several errors like:
"C:\Users\Joaquim\Documents\CodeBlocks\test\properties.h|9|error: 'property' is not a class template"

None of the codes that I posted are standalone. They are for demonstration purposes, i.e., I'm demonstrated how to accomplish what I talked about in the post, it wasn't meant to be used as is. For example, the different versions of "property" class template that I showed can come and replace your original version, within your original code (with its includes and the PropTest class, etc..).

sorry can you, please, give me a nice link for i learn how can i overload the operators?

The C++ wikibook has a pretty complete overview of operator overloading.

finally i have the function working:

friend istream &operator>>( istream  &input, property &d )
      {
         ValueType v;

            input >> v;

         d = v;
         return input;
      }

these function works, but not with strings ando know why;)
see these new function:

friend istream &operator>>( istream  &input, property &d )
      {
         ValueType v;
         if (typeid(v).name()== typeid(string).name() )
         {
             input >> (string) v;
         }
         else
         {
            input >> v;
         }
         d = v;
         return input;
      }

like you see i'm trying see if the 'v' is 'string'. but i get several errors in 'input >> (string) v;', why?

like you see i'm trying see if the 'v' is 'string'. but i get several errors in 'input >> (string) v;', why?

There are two reasons why this fails.

1) All code in the function body of a template must compile for each type it is instantiated with. In other words, if the value type is int, then the code which says (string)v still needs to compile correctly, where v is an integer. Obviously, only an insane compile would let that slide without errors (or warnings, if you tell it to be C-style permissive).

2) Even just for the case that the value type is string, it won't work (even if the first issue didn't apply). When you cast it to a string, it actually creates a temporary object of type string from the value v. And a temporary object (also called an "rvalue") cannot be used in an expression like input >> because it needs to assign a value to that temporary, but a temporary cannot be assigned to. That's the rule (and there are good reasons for that).

these function works, but not with strings ando know why;)

Why not? It's a perfectly fine function, and should work for strings. What is it that is not working with strings? What happens? And why do you want it to do?

for cout, i must use '(string)', or i get errors(that's why that 'if'). anotherthing: i can't use: 'getline(cin, a.Name) ;', why?

finally i can use 'getline':

friend istream& getline (istream&  is, property& str)
      {
          ValueType v;
        getline(is,v);

         str = v;
         return is;
      }

how can i change the string header?
(i'm using the GNU)
why??? for overloading operator+ and cout and then i don't need write '(string)';)

If you need to implement different behavior for different types, you can use a separate function with overloading. This is what I mean:

template <typename T>
void read_from_stream(std::istream& is, T& value) {
  is >> value;
};

void read_from_stream(std::istream& is, std::string& value) {
  std::getline(is, value);
};

And then, in your property's stream function, you just do this:

  friend istream &operator>>( istream  &input, property &d )
  {
     ValueType v;
     read_from_stream(input, v);
     d = v;
     return input;
  }

The compiler will select the correct version of read_from_stream depending on the value-type. This is the standard way to do this.

thanks. now i must do anotherthing with these class;)
can i put these lines together with property?

Name.setContainer(this);
    Name.setter(&PropTest::setName);
    Name.getter(&PropTest::getName);


property<PropTest,string,READ_WRITE> Name;

instead these code, i want do:
property<PropTest,string,getName,setName, this, READ_WRITE> Name;
(put all together)

so i think that i must change:

template <typename Container, typename ValueType,typename get, typename set, int nPropType>

right?

and in property construtor:

property()
    {
        m_cObject = this;
        Set = set;
        Get = get;
    }

i'm right?

i'm trying do these:

#include <assert.h>
#include <iostream>
#include <typeinfo>
#include <string>

#define READ_ONLY 1
#define WRITE_ONLY 2
#define READ_WRITE 3

using namespace std;

template <typename Container, typename ValueType, typename getfunction=NULL, typename setfunction=NULL,  int nPropType=3>
class property
{
public:
    property()
    {
        m_cObject = assert(Container);
        Set = setfunction;
        Get = getfunction;
    }

    //-- This to set a pointer to the class that contain the
    //   property --




    void setContainer(Container* cObject)
    {
        m_cObject = cObject;
    }

    //-- Set the set member function that will change the value --
    void setter(void (Container::*pSet)(ValueType value))
    {
        if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
            Set = pSet;
        else
            Set = NULL;
    }

    //-- Set the get member function that will retrieve the value --
    void getter(ValueType (Container::*pGet)())
    {
        if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
            Get = pGet;
        else
            Get = NULL;
    }

    //-- Overload the '=' sign to set the value using the set
    //   member --
    ValueType operator =(const ValueType& value)
    {
        assert(m_cObject != NULL);
        assert(Set != NULL);
        (m_cObject->*Set)(value);
        return value;
    }


    //-- To make possible to cast the property class to the
    //   internal type --
    operator ValueType()
    {
        assert(m_cObject != NULL);
        assert(Get != NULL);
        return (m_cObject->*Get)();
    }

    friend istream &operator>>( istream  &input, property &d )
    {
        ValueType v;
        input >>v;
        d = v;
        return input;
    }

    friend istream& getline (istream&  is, property& str)
    {
        ValueType v;
        getline(is,v);
        str = v;
        return is;
    }

private:
  Container* m_cObject;  //-- Pointer to the module that
                         //   contains the property --
  void (Container::*Set)(ValueType value);
                         //-- Pointer to set member function --
  ValueType (Container::*Get)();
                         //-- Pointer to get member function --
};

and the class:

class PropTest
{
public:
  int getCount()
  {
    return m_nCount;
  }
  void setCount(int nCount)
  {
    m_nCount = nCount;
  }
  property<PropTest,int,&getCount,&setCount> Count;

  string getName()
  {
    return strName;
  }
  void setName(string sName)
  {
    strName = sName;
  } 
  property<PropTest,string,&getName,&setName> Name;

private:
  int m_nCount;
  string strName;
};

what i'm doing wrong in my template?

now it's more cool:

/*how use properties:

- inside class constructor do these:
    PropertyName.setContainer(this);

- inside the class but outside the class members(but after the GetFunction and\or SetFunction) do these:
    property <ClassName,PropertyType,&ClassName::SetFunction,&ClassName::GetFunction> PropertyName;

- more information:
    - for ReadOnly we use 'nullptr'(and not NULL, because they are pointers) on &ClassName::GetFunction as argument;
    - for WriteOnly we use 'nullptr'(and not NULL, because they are pointers) on &ClassName::SetFunction as argument;

*/


#ifndef PROPERTY_H_INCLUDED

#define PROPERTY_H_INCLUDED

#include <iostream>
#include <assert.h>

using namespace std;

template <typename Container, typename ValueType, void (Container::*setptr)(ValueType t),ValueType (Container::*getptr)()>
class property
{
public:
    property()
    {
        m_cObject= NULL;
        Set = setptr;
        Get = getptr;
    }

    void setContainer(Container* cObject)
    {
        m_cObject = cObject;
    }

    //-- Overload the '=' sign to set the value using the set
    //   member --
    ValueType operator =(const ValueType& value)
    {
        assert(m_cObject != NULL);
        assert(Set != NULL);
        (m_cObject->*Set)(value);
        return value;
    }


    //-- To make possible to cast the property class to the
    //   internal type --
    operator ValueType()
    {
        assert(m_cObject != NULL);
        assert(Get != NULL);
        return (m_cObject->*Get)();
    }

    friend istream &operator>>( istream  &input, property &d )
    {
        ValueType v;
        input >>v;
        d = v;
        return input;
    }

    friend istream& getline (istream&  is, property &str)
    {
        ValueType v;
        getline(is,v);
        str = v;
        return is;
    }

private:
  Container* m_cObject;  //-- Pointer to the module that
                         //   contains the property --
  void (Container::*Set)(ValueType value);
                         //-- Pointer to set member function --
  ValueType (Container::*Get)();
                         //-- Pointer to get member function --
};

#endif // PROPERTY_H_INCLUDED

but seems that i can't use 'this' in template header:(
but i have seen some code that use it.. but now i don't remember where is it:(

i have 2 questions:

1 - why some C++ PRO don't advice me use these code?(making properties)

2 - can i put these 2 parameters optionals?
- void (Container::setptr)(ValueType t)
- ValueType (Container::
getptr)()

i try assigment them to NULL, but i can't use an empty argument, because gives me errors. can anyone explain to me more?

(sorry Mike_2000_17)
Mike_2000_17: "Why not? It's a perfectly fine function, and should work for strings. What is it that is not working with strings? What happens? And why do you want it to do?"
because i need casting the string, or the 'cout' will give me an error. i don't know why. but with casting it's working fine;)

1 - why some C++ PRO don't advice me use these code?(making properties)

Because it's awkward (as you've discovered), unnecessary, and a complete solution isn't as good as what you'd get with another language like C#. C++ "pros" do without excessively awkward fluff.

1 - why some C++ PRO don't advice me use these code?(making properties)

Properties, like they exist in Delphi and C#, are certainly nice and convenient, but not an essential part of any language. I mean, they don't enable any particularly interesting coding techniques or patterns, i.e., they just make the code that uses the property a bit nicer and more uniform. There are some encapsulation benefits to properties, but nothing ground-breaking either.

In C++, you can achieve a very basic implementation of properties, either mimicking Delphi-style properties (with a property class template) or C#-style properties (with nested classes), as seen here. But in all cases, the basic mechanism used to "look like a variable" is the combination of an assignment operator (for writing) and an implicit conversion operator (for reading). This mechanism does a decent job, and is used for many "value-wrappers", such as my "award-winning" lockable class template. But, the result is definitely not perfect, and there are definitely compromises to be made with regards to how good things will look at the places where the properties are used. And since the whole point of properties is to achieve a perfectly uniform syntax where you use them. Any compromise is unacceptable.

The bottom line is that if you can't achieve an implementation of properties that give you something more intuitive, clean and painless than a "standard" good old-fashion get/set pair (which everyone is used to and familiar with), then it's not an improvement over existing practice. Most "pros" realize that within the rules of the language, you cannot really get much better than that typical assign-op / implicit-conversion mechanism. And that is simply not good enough because it leads to a number of issues that violate intuition and cleanliness, and can often fail, requiring a fall-back to a more explicit syntax. In other words, it makes the user-experience worse, not better.

Most "pros" would agree that to have decent support for "properties" in C++, it would require additional language syntax, i.e., a change to the C++ language standard. And I believe there have been a few concrete proposals for it too. And MSVC already has an extension for Delphi-style properties. But as far as standardization goes, I think that too many people want too many different things.

2 - can i put these 2 parameters optionals?

No, you cannot. C++ allows (member-)function pointers as template arguments, and it allows template arguments to have default values, but not both, and there is a good reason for that. The way that C++ allows for function pointers as template arguments is by generating a kind of compile-time "pointer" to the function you pass to the template. It is not really a conventional pointer, at least, not until the final linking steps are applied, i.e., until the point at which the linker knows the actual value of that function pointer and can substitute it into the code. Giving a default value to a function pointer template argument is tricky because that default value must be a valid function pointer, i.e., a pointer to an actual function (with what we call "external linkage"). It cannot be the "null" pointer.

In your case, there isn't much you can do except provide multiple versions of your property template, with different arguments. For example, you could have a readonly-property and a readwrite-property, as two separate class templates (taking a get function and a get/set pair, respectively). Which is pretty much what I already showed before.

Also, if you take the function pointers as template arguments, you don't need to have the "Get" and "Set" data members, you can simply use the "getptr" and "setptr" directly instead (and you don't have to check that they are null, because they cannot be, as I just explained). Here is a simple version:

template <
  typename Container, 
  typename ValueType, 
  ValueType (Container::*getptr)(),
  void (Container::*setptr)(ValueType) >
class rw_property
{
public:
    rw_property(Container* cObject) : m_cObject(cObject) { }

    //-- Overload the '=' sign to set 
    //   the value using set member --
    ValueType operator =(const ValueType& value) {
        (m_cObject->*setptr)(value);
        return value;
    }

    //-- To make possible to cast the 
    //   property to the internal type --
    operator ValueType() {
        return (m_cObject->*getptr)();
    }

private:
  Container* m_cObject;  //-- Pointer to the module that
                         //   contains the property --
};


template <
  typename Container, 
  typename ValueType, 
  ValueType (Container::*getptr)() >
class ro_property
{
public:
    ro_property(Container* cObject) : m_cObject(cObject) { }

    //-- To make possible to cast the 
    //   property to the internal type --
    operator ValueType() {
        return (m_cObject->*getptr)();
    }

private:
  Container* m_cObject;  //-- Pointer to the module that
                         //   contains the property --
};

thanks for all.. thanks to both

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.