By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,423 Members | 1,697 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,423 IT Pros & Developers. It's quick & easy.

C++ Property template

P: n/a
Hello,

This is my first attempt at template programming so please bear with me.
This is what I have so far:

Property.h --------------------------

#ifndef PROPERTY_H_
#define PROPERTY_H_

enum Access{ READ, WRITE, FULL };

template<typename T, Access type = FULL>
class Property
{
public:
Property(const T& val, T (*getter)(T) = defaultGet, T (*setter)(T,
T) = defaultSet ): value(val) { Get = getter; Set = setter; }
virtual operator T() { return Get(value); }
virtual T operator=( T& val ) { return Set(value, val); }
protected:
T value;
T (*Get) (T);
T (*Set) (T, T);
static T defaultGet(T val) { return val; }
static T defaultSet(T dest, T source) { dest = source; }
};

#endif
and here is my test program:

main.cpp ---------------------------------

#include <cstdlib>
#include <iostream>

#include "Property.h"

static int anotherGetter(int value) { return 10; }

int main(int argc, char *argv[])
{
Property<int> t(1);
std::cout << t << std::endl;
t = 5;
std::cout << t << std::endl;
t = 2;
std::cout << t << std::endl;
// Up to here everything works fine but:
Property<int> f(1, anotherGetter);
std::cout << f << std::endl; // This returns 10 like it's supposed to
f = 5;
std::cout << f << std::endl;
// But this returns 5 not 10
f = 2;
std::cout << f << std::endl;
// And again this returns 2 not 10.
system("pause");
}

My question is why does it work the way I intended the first time but not
the second or third time?

Any help would be appreciated
Nov 23 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
t=5,t=2,f=5,f=2 calls your copy constructor (your constructor is used
as a copy constructor)

Nov 23 '05 #2

P: n/a
On Tue, 22 Nov 2005 06:58:15 -0500, "Brent Ritchie"
<br**********@personainternet.com> wrote:
Hello,

This is my first attempt at template programming so please bear with me.
This is what I have so far:

Property.h --------------------------

#ifndef PROPERTY_H_
#define PROPERTY_H_

enum Access{ READ, WRITE, FULL };

template<typename T, Access type = FULL>
class Property
{
public:
Property(const T& val, T (*getter)(T) = defaultGet, T (*setter)(T,
T) = defaultSet ): value(val) { Get = getter; Set = setter; }
virtual operator T() { return Get(value); }
virtual T operator=( T& val ) { return Set(value, val); }
protected:
T value;
T (*Get) (T);
T (*Set) (T, T);
static T defaultGet(T val) { return val; }
static T defaultSet(T dest, T source) { dest = source; }
};

#endif
and here is my test program:

main.cpp ---------------------------------

#include <cstdlib>
#include <iostream>

#include "Property.h"

static int anotherGetter(int value) { return 10; }

int main(int argc, char *argv[])
{
Property<int> t(1);
std::cout << t << std::endl;
t = 5;
std::cout << t << std::endl;
t = 2;
std::cout << t << std::endl;
// Up to here everything works fine but:
Property<int> f(1, anotherGetter);
std::cout << f << std::endl; // This returns 10 like it's supposed to
f = 5;
std::cout << f << std::endl;
// But this returns 5 not 10
f = 2;
std::cout << f << std::endl;
// And again this returns 2 not 10.
system("pause");
}

My question is why does it work the way I intended the first time but not
the second or third time?

Any help would be appreciated


Your assignment

f = 5;

is inadvertently (to you) interpreted as

f = Property<int>(5);

instead of

f.operator=(5);

In other words, a temporary Property<int> object is created, which is then
assigned to f.

The reason for this behavior is that your assignment operator takes a
non-const T&. Make sure that your assignment operators are in the form:

T& operator=(const T&);

A constructor that can be called with a single argument is also likely to
cause this kind of automatic temporary object creation. Perhaps you should
declare your constructor explicit.
Nov 23 '05 #3

P: n/a
Brent Ritchie wrote:
Property<int> f(1, anotherGetter);
std::cout << f << std::endl; // This returns 10 like it's supposed to
f = 5;
std::cout << f << std::endl;
// But this returns 5 not 10


I guess the problem is this:
The expression 'f = 5' creates a new Property object using the copy
constructor and assigns it to 'f'. Since you are setting the default
getter in the copy constructor, it returns 'value' and not '10', so the
output is '5'.

Try making your copy constructor explicit, then it must not be used for
type conversion. Another issue might be that AFAICT you operator= has a
wrong signature: 'val' should be of type reference-to-const T, not
reference-to-T.

Hope that helps,
Matthias
Nov 23 '05 #4

P: n/a
Matthias Kaeppler wrote:
Try making your copy constructor explicit, then it must not be used for
type conversion.


One more note about copy constructors:

Although your copy constructor has /three/ formal parameters, it can be
called by the client only taking /one/ argument, since you're assigning
default values to parameters two and three.
Since every copy constructor which can be called using one argument
qualifies for implicit type conversion, you should make it 'explicit',
unless you want type conversion to happen (this form of conversion can
be very useful, but it's also error prone because it's hard to
detect--as you probably noted yourself now).

One more C++ subtlety which pops up now and then :)

Regards,
Matthias
Nov 23 '05 #5

P: n/a
Thanks all,

This is what I have so far for my C++ Property Template:

Property.h-------------------------

#ifndef PROPERTY_H_
#define PROPERTY_H_

enum Access{ READ, WRITE, FULL };

template<typename T, Access type = FULL>
class Property
{
public:
explicit Property( const T& val,
const T (*getter)(const T&) = defaultGet,
const T (*setter)(T&, const T&) = defaultSet )
: value(val)
{
if (getter == NULL)
{
Get = defaultGet;
}
else { Get = getter; }
if ( setter == NULL )
{
Set = defaultSet;
}
else
{
Set = setter;
}
}

explicit Property( Property *val )
{
val.value = this->value;
val.Get = this->Get;
val.Set = this->Set;
}

virtual operator T()
{
return Get(value);
}
virtual T operator=( const T& val )
{
return Set(value, val);
}

protected:
const T (*Get) ( const T& );
const T (*Set) ( T&, const T& );
T value;

static const T defaultGet(const T& val)
{
return val;
}

static const T defaultSet(T& dest, const T& source)
{
dest = source;
return dest;
}

};

#endif

main.cpp-----------------------------

#include <cstdlib>
#include <iostream>

#include "../Property.h"

static const int anotherGetter(const int& value) { return value * -1; }
static const int anotherSetter(int& value, const int& value2 ) { value +=
value2; return value; }

int main(int argc, char *argv[])
{
int i = 0;

Property<int> a(2);
std::cout << "Property<int> a(2)" << std::endl;
std::cout << "Input value to test default set functionality: ";
std::cin >> i;
a = i;
std::cout << "Testing default get functionality: ";
std::cout << a << std::endl << std::endl;

Property<int> b(2, anotherGetter);
std::cout << "Property<int> b(2, anotherGetter)" << std::endl;
std::cout << "Input value to test default set functionality: ";
std::cin >> i;
b = i;
std::cout << "Testing anotherGetter functionality: ";
std::cout << b << std::endl << std::endl;

Property<int> c(2, NULL, anotherSetter);
std::cout << "Property<int> c(2, NULL, anotherSetter)" << std::endl;
std::cout << "Input value to test anotherSetter functionality: ";
std::cin >> i;
c = i;
std::cout << "Testing default get functionality: ";
std::cout << c << std::endl << std::endl;

Property<int> d(2, anotherGetter, anotherSetter);
std::cout << "Property<int> d(2, anotherGetter, anotherSetter)" <<
std::endl;
std::cout << "Input value to test anotherSetter functionality: ";
std::cin >> i;
d = i;
std::cout << "Testing anotherGetter functionality: ";
std::cout << d << std::endl << std::endl;

Property<int> x = d;
std::cout << x << std::endl;
x = 2;
std::cout << x << std::endl;
x = 1;
std::cout << x << std::endl;
system("pause");

return 0;

}

Next, I'm going to add the overloaded versions of this template for
read-only and write-only access. Then I'm going to start testing all
primitives not just int. Then I have to start testing user defined classes.
<shutters>

Any comments on what I have so far? Anything you see as potentially
broken? Feature changes/requests ;) ? Anyone think this might be potentially
useful to anyone but me?

Also if you notice this compiles nicely with no warnings even with -Wall
turned on. I think thats a first for me!

Anyways, Thanks for all the help. This template programming isn't all
that different from regular programming but it has it's nuances though.
Nov 23 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.