C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

C# Properties, inner classes and CRTP

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Guest






PostPosted: Sat Dec 16, 2006 10:10 am    Post subject: C# Properties, inner classes and CRTP Reply with quote



[proposal for C++0x or later]
I want to propose and discuss the following new language features that,

as a side effect, allow an easy and flexible definition of C# like
properties (that is even better than C#) in C++ classes.

Btw, I started the same thing in comp.std.c++, let's see which one is
more successful.

QUICK SUMMARY

I propose to introduce

- A new syntax for anonymous inner classes that derive from a base
class.

- The keyword "nested", that tells a nested class to store a hidden
reference to the enclosing object (like in java)

- The keyword "enclosing_object" using either the hidden reference, or
a mechanism equivalent to the "offsetof" macro trick described in 1.2
below. (possible alternative: "::this" ?)

- The keyword "fragmental", introducing a mechanism to replace the CRTP

(curiously recurring template pattern). Even more, fragmental classes
allow multiple inheritance without the usual bloat of the vtable
architecture.

TOC.

1) C# like Properties in classic C++.
1.1) Implementation using runtime polymorphism.
1.2) Implementation using CRTP and the offsetof Macro.

2) The proposed new language features.
2.1) Anonymous classes derived from base class
2.2) The "nested" keyword.
2.3) The "enclosing_object" keyword.
2.4) The "fragmental" keyword - a syntactical replacement for the CRTP
mechanism.

3) C# like Properties using the new language features.

4) Other examples that benefit from the new language features.
4.1) A Simple State Machine
4.2) A nice Workaround for the lack of virtual function templates in
C++

================================================

1) C# like Properties in classic C++
Consider the following two examples that try to implement C# like
properties with classic C++ syntax.

-------------------------------------------------------------

1.1) Implementation using runtime polymorphism.

struct Float {
virtual void set(float f)=0;
virtual float get()=0;
Float& operator += (float f) {
set(get()+f);
return *this;
}
Float& operator = (float f) {
set(f);
return *this;
}
...

};

class C {
float angle_;
public:
C() {angle.enclosing_object=this;}
struct Angle : Float {
C* enclosing_object;
void set(float f) {
while(f>=360) f-=360;
while(f<0) f+=360;
enclosing_object->angle_=f;
}
float get() {return enclosing_object->angle_;}
} angle;

};

int main() {
C c;
c.angle = -45; // -> c.angle_ == 315
c.angle += 180; // -> c.angle_ == 135
c.angle += 270; // -> c.angle_ == 45

}

Problems:
- Performance overhead because of vtable lookup that is not nessecary
from a technical perspective.
- We need to store and take care of the "enclosing_object" pointer ->
memory overhead, and possibility of errors.

-------------------------------------------------------------

1.2) Implementation using CRTP and the offsetof Macro.

template<class Derived> struct Float {
Derived* derived() {
return static_cast<Derived*>(this);
}
Derived& operator += (float f) {
derived()->set(derived()->get()+f);
return *derived();
}
Derived& operator = (float f) {
derived()->set(f);
return *derived();
}
...

};

class C {
float angle_;
public:
struct Angle : Float<C::Angle> {
C* enclosing_object() {
const static int offset = offsetof(C, angle);
return
reinterpret_cast<C*>(reinterpret_cast<char*>(this)-offset);
}
void set(float f) {
while(f>=360) f-=360;
while(f<0) f+=360;
enclosing_object()->angle_=f;
}
float get() {return enclosing_object()->angle_;}
} angle;

};

int main() {
C c;
c.angle = -45; // -> c.angle_ == 315
c.angle += 180; // -> c.angle_ == 135
c.angle += 270; // -> c.angle_ == 45

}

Problem: This solution is quite efficient, but the code is not that
nice to read. Especially, we don't like to depend on CRTP and macros
for an everyday problem.

===========================================

2) The new language features

I propose to introduce
- A new syntax for anonymous inner classes that derive from a base
class.
- The keyword "nested", that tells a nested class to store a hidden
reference to the enclosing object (like in java)
- The keyword "enclosing_object" using either the hidden reference, or
a mechanism equivalent to the "offsetof" macro trick described above.
- The keyword "fragmental", introducing a mechanism to replace the CRTP

(curiously recurring template pattern). Even more, fragmental classes
allow multiple inheritance without the usual bloat of the vtable
architecture.

You don't need to like the wording, at this point *g*.
I was talking about two, not four new features, because I think the
first three of them should actually be seen as one.

-------------------------------------------------------------

2.1) Anonymous classes derived from base class
In classic C++, anonymous classes cannot derive from a base class.

struct Base {};

class C {

struct {
} m0, m1, m2; // no base class

struct M : Base {
} m0, m1, m2; // not anonymous

};

I propose to allow the following syntax.

struct Base {};

class C {
Base m {
}; // [*]. The (anonymous) type of member m is derived from class
Base
Base {
} m0, m1, m2; // [**]. The (anonymous) type of members m0, m1, m2 is

derived from class Base

};

Currently this would be invalid code, so it will not break existing
programs.

2.2) The "nested" keyword. This keyword is used in a class or struct
definition, to indicate that there should be a hidden reference to the
enclosing object, that is initiated automatically, like in Java.

class C {
nested struct M {};

};

-------------------------------------------------------------

2.3) The "enclosing_object" keyword. This keyword returns a pointer to
the enclosing object. Technically, this can work in two ways:
- for member classes that are defined as "nested", the
"enclosing_object" keyword will just return the hidden reference.
- for anonymous member classes defined in the first way (2.1 [*]), the
"enclosing_object" keyword uses a mechanic that is equivalent to the
offsetof macro trick. The anonymous definition guarantees a fixed
adress difference to the enclosing object.

struct Base {};

class C {

void foo() {..}

//-----------------------------------------------------------------
// classic C++ inner class definitions

nested struct M : Base {
void foo() {enclosing_object->foo();} // use the hidden reference
};

struct M : Base {
void foo() {enclosing_object->foo();} // error: M needs to be
declared 'nested'.
};

struct {
void foo() {enclosing_object->foo();} // uses adress difference of

C and m.
} m;

struct {
void foo() {enclosing_object->foo();} // uses adress difference of

C and m0.
} m0, m1, m2; // error: no more instances than m0 allowed, if you
use the enclosing_object keyword

//-----------------------------------------------------------------
// new way to define anonymous inner classes

Base m {
void foo() {enclosing_object->foo();} // use the adress difference

of C and m
};

nested Base m {..}; // error: invalid use of keyword "nested" -
hidden reference would be redundant

nested Base {
void foo() {enclosing_object->foo();} // use the hidden reference
} x0, x1, x2;

Base {
void foo() {enclosing_object->foo();} // use the adress difference

of C and x.
} x;

Base {
void foo() {enclosing_object->foo();} // use the adress difference

to x3.
} x3, x4, x5; // error: no more instances than x3 allowed, if you
use the enclosing_object keyword

};

An alternative to the keyword "enclosing_object" would be the syntax
::this == enclosing_object
::::this == enclosing_object->enclosing_object

-------------------------------------------------------------

2.4) The "fragmental" keyword - a syntactical replacement for the CRTP

mechanism.
A fragmental class is not a type itself, but is used as a building
block to create new types by (multiple) inheritance. Similar to a CRTP
(curiously recurring template pattern), a fragmental class has
compile-time-access to (specified) methods of the child class.

In a class or struct definition ("fragmental class F {...};") the
keyword means
- It is not possible to use F, F& or F* as a type, except for methods
and members of F itself. There can be neither instances, nor
references, nor pointers.
- F can derive from any other classes or structs (fragmental or not),
and any other class or struct (fragmental or not) can derive from F,
with the usual restrictions.
- The compiler waits for a non-fragmental child class to derive from F,

before any methods are compiled.
- F derives the vtable pointers from all its base classes, but it does
not define any vtable pointer for its own virtual methods.

For any class C deriving from one or more classes (fragmental and
non-fragmental),
- Declarations in the fragmental base classes hide/override
declarations with the same name/signature in the non-fragmental base
classes.
- C stores only one vtable pointer for all the virtual methods defined
in fragmental base classes, or in C itself. For the rest of direct or
indirect base classes that are not fragmental, the compiler tries to
minimize the number of vtable pointers in C (as usual).
- For members of a fragmental base class F of C, any occurance of F, F&

or F* in this declaration is replaced by C, C& or C*.

For methods of a fragmental class F ("fragmental void foo()=0;") the
keyword means
- Any non-fragmental class deriving from F must give an implementation
of the method foo().
- Any other method in F can call the method foo(). If doing so, the
function call is redirected to the first implementation of foo() in a
non-fragmental class deriving (directly or indirectly) from F. Unlike
with virtual functions, this happens at compile time (and thus is
equivalent to a CRTP mechanism).

=========================================================

3) C# like Properties using the proposed new language features.

fragmental struct Float {
fragmental void set(float f)=0;
fragmental float get()=0;
Float& operator += (float f) {
set(get()+f);
return *this;
}
Float& operator = (float f) { // return type will be replaced by C&,

when deriving C from Float
set(f);
return *this;
}
...

};

class C {
float angle_;
public:
// anonymous inner class derived from 'Float', instantiated as member

'angle'
Float angle {
void set(float f) {
while(f>=360) f-=360;
while(f<0) f+=360;
enclosing_object->angle_=f; // using the adress difference of
C and angle
}
float get() {
return enclosing_object->angle_; // using the adress difference
of C and angle
}
};

};

int main() {
C c;
c.angle = -45; // -> c.angle_ == 315
c.angle += 180; // -> c.angle_ == 135
c.angle += 270; // -> c.angle_ == 45

}

This is much more efficient than 1.1, and much easier to read than 1.2
imo.

=========================================================

4) Other examples that benefit from the new language features.
Here is just two of them, but I'm sure more is possible.

-----------------------------------------------------------------

4.1) A Simple State Machine
The new mechanisms allow the easy translation of a state machine into
code, using

struct SimpleStateMachine
{
SimpleStateMachine() {current_state=state_A;}
void step() {current_state->step();}

private:
struct State {
virtual void step()=0;
} *current_state;

State state_A { // derived from struct State
virtual void step() {
enclosing_object->current_state=state_B;
}
};

State state_B { // derived from struct State
virtual void step_v() {
enclosing_object->current_state=state_A;
}
};

};

-----------------------------------------------------------------

4.2) A nice Workaround for the lack of virtual function templates in
C++

template<
typename T
Quote:
fragmental struct F_Interface_T {

// overloading instead of function template
virtual void foo_v(T)=0;

};

// multi-inheritance, but only one vtable pointer needed, thanks
fragmental classes
struct Interface : F_Interface_T<C0>, F_Interface_T<C1>,
F_Interface_T<C2> {
template<typename T> void foo() {foo_v(T);}

};

template<
typename T
Quote:
fragmental struct F_Imp_T : public virtual Base {

virtual void foo_v(T) {
Final::foo_imp<T>();
}

};

struct F_Imp : F_Imp_T<C0>, F_Imp_T<C1>, F_Imp_T<C2> {

};

// user code
struct MyClass : F_Imp {
template<typename T> void foo_imp() {
... // implementation
}

};


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Todd Gardner
Guest





PostPosted: Sun Dec 17, 2006 12:23 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote



stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:
Quote:
[proposal for C++0x or later]
I want to propose and discuss the following new language features that,

as a side effect, allow an easy and flexible definition of C# like
properties (that is even better than C#) in C++ classes.

[snipped example]

Quote:
Problems:
- Performance overhead because of vtable lookup that is not nessecary
from a technical perspective.

If virtual function calls are draining enough of your runtime to make a
significant impact, why use inheritance for this problem at all? And if
they are not, why introduce new features that don't have an effect?

Quote:
- We need to store and take care of the "enclosing_object" pointer -
memory overhead, and possibility of errors.

(as a note, I would prefer a reference to C, not the pointer)
So, hacking up the post a bit, later you want:

Quote:
2.2) The "nested" keyword. This keyword is used in a class or struct
definition, to indicate that there should be a hidden reference to the
enclosing object, that is initiated automatically, like in Java.

to solve this problem. But how does the hidden reference take up less
space than the explicit one? Also, considering the reference
implementation, the only possibililty of error this would solve is if
coder didn't write the constructor correctly which wouldn't seem an
easy error to make, and be detectable at compile time.


Quote:

2.4) The "fragmental" keyword - a syntactical replacement for the CRTP

mechanism.
A fragmental class is not a type itself, but is used as a building
block to create new types by (multiple) inheritance. Similar to a CRTP
(curiously recurring template pattern), a fragmental class has
compile-time-access to (specified) methods of the child class.


[snip]

Quote:
- F derives the vtable pointers from all its base classes, but it does
not define any vtable pointer for its own virtual methods.

A class doesn't have a vtable pointer, and (some) objects has a vtable
pointer. And each object only has one vtable pointer. I don't quite
understand what you are trying to accomplish here. Are you trying to
make it so F doesn't define a vtable?

[snip]

Quote:
- C stores only one vtable pointer for all the virtual methods defined
in fragmental base classes, or in C itself. For the rest of direct or
indirect base classes that are not fragmental, the compiler tries to
minimize the number of vtable pointers in C (as usual).

Objects of type C only have one vtable pointer. Attempting to reduce
that number might prove more tricky.

[snip]

Quote:
3) C# like Properties using the proposed new language features.

[snipped example]

Quote:
This is much more efficient than 1.1, and much easier to read than 1.2
imo.

So, the only way this could be more efficient is if it avoided virtual
function calls (and then most likely only minimally). But you haven't
explained a mechanism by which it avoids the virtual function calls.

Todd


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Sun Dec 17, 2006 4:09 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote



The answers are already in my original post, honestly. But anyway, I'll
try to explain.

Todd Gardner wrote:
Quote:

If virtual function calls are draining enough of your runtime to make a
significant impact, why use inheritance for this problem at all?

A primary goal of inheritance is to avoid code redundancy (that causes
more trouble than just work, btw). Another goal is to have a common
handle to objects of different types, that redirects virtual function
calls to the specific implementation. Only the second issue cannot be
solved without the overhead of vtable lookup. We are talking about the
first issue, that can be solved without - as demonstrated in the CRTP
example 1.2.

Talking about properties. We would like to have an object that behaves
like a float value from outside, but with very individual interior
mechanics. Having different float-like properties in different classes,
these would all allow operations like +=, -=, *=, /=, =, +, -, *, etc.
But inside, they would all work different. For instance, the class C
from above could have one C::angle_rad and one C::angle_deg property,
each using the same internal value C::angle_deg_. Without Float as a
base class, we would need to implement all of the operators twice.

Now we only need to re-implement the methods set() and get() - but for
this to work, it is necessary that the methods defined in the base
class have access to the methods of the implementation.

The most common way to solve this are virtual functions - therefore
example 1.1. The more efficient way is CRTP, as shown in example 1.2.
The difference is, only the virtual function solution gives us a common
handle for different implementations - a pointer to the base class. In
our case, we don't need this common handle, thus CRTP is the solution
of choice (if performance matters).

My message is, that CRTP is a clumsy workaround, for a missing language
feature. Every time I use this mechanism, I see myself making one error
after the other, just because there are so many things to care about.

Quote:
- We need to store and take care of the "enclosing_object" pointer -
memory overhead, and possibility of errors.

(as a note, I would prefer a reference to C, not the pointer)
So, hacking up the post a bit, later you want:

2.2) The "nested" keyword. This keyword is used in a class or struct
definition, to indicate that there should be a hidden reference to the
enclosing object, that is initiated automatically, like in Java.

to solve this problem. But how does the hidden reference take up less
space than the explicit one? Also, considering the reference
implementation, the only possibililty of error this would solve is if
coder didn't write the constructor correctly which wouldn't seem an
easy error to make, and be detectable at compile time.

If you read my examples at the end of the post, you will notice that
none of them uses the nested keyword. In 1.2, I explain why this is not
necessary (offsetof macro). The primary idea of the 'enclosing_object'
keyword is providing a type-safe and more readable replacement of the
offsetof mechanism. In my examples 3 and 4.*, using the
enclosing_object keyword would generate a machine code that is
technically equivalent to the offsetof macro trick in 1.2 - thus, no
hidden reference needs to be stored.

About the 'nested' keyword. The offsetof-mechanism does only work in
very special cases. For the general inner class, it is necessary to
maintain a reference to the enclosing class. The question of
introducing the 'nested' keyword is a matter of comfort, compared to an
explicit reference. Any java programmer would agree that the hidden
reference makes programming easier. What if we have different
constructors, and different members that need this pointer - why take
care of all these reference initialisations yourself??

In 2.3, you can see the different ways of using 'enclosing_object' with
or without a hidden reference.

Quote:

2.4) The "fragmental" keyword - a syntactical replacement for the CRTP

mechanism.
A fragmental class is not a type itself, but is used as a building
block to create new types by (multiple) inheritance. Similar to a CRTP
(curiously recurring template pattern), a fragmental class has
compile-time-access to (specified) methods of the child class.


[snip]

- F derives the vtable pointers from all its base classes, but it does
not define any vtable pointer for its own virtual methods.

A class doesn't have a vtable pointer, and (some) objects has a vtable
pointer. And each object only has one vtable pointer. I don't quite
understand what you are trying to accomplish here. Are you trying to
make it so F doesn't define a vtable?

Maybe it will ease our conversation, if you read more about the vtable
architecture and the curiously recurring template pattern (CRTP).. I
recently did so, and had to correct some of my conceptions.

The vtable pointer is implemented as a hidden non-static member of a
class with virtual functions. Of course, for any non-static class
member, it is not the class but the instance where this member is
stored - I thought this is clear from my explanation?

Now, if C is derived from multiple base classes B_1...B_n with virtual
methods B_1::foo_1() .. B_n::foo_n(), C needs one vtable for each of
these base classes. And instances of C store one vtable pointer for
each of these base classes. This seems strange, but if you think about
it (or just read somewhere), you will agree that it is necessary. If
you have a poiner B_i* b, the virtual function call b->foo_i() will
trigger a vtable lookup in the specific table for the part of C that is
derived from B_i.

Now, if C is derived from multiple fragmental classes F_1...F_n with
virtual methods foo_1()...foo_n(), it is enough to have one vtable for
all these virtual functions. The reason is, we cannot have a pointer of
type F_i*, as F_i is a fragmental class. So, it will never be necessary
to redirect a virtual function call from F_i to its implementation in C
at runtime.

Why would we want the fragmental class to have virtual functions at
all, you might ask. Let us think about the two motivations for
inheritance - avoiding code redundancy, and redirecting function calls
at runtime. My suggestions are aimed only at the first of these two.
Imagine you want a class that has different versions of a virtual
method - for different argument types, for instance - like virtual
foo(T<1>), .., virtual foo(T<n>). Now, instead of explicitly defining
each of these methods, you can create a fragmental class template F<i>
to define the method virtual foo(T<i>), and then multi-derive from F<1>
... F<n> to let C have all versions of foo(*). (see example 4.2).

Quote:

[snip]

- C stores only one vtable pointer for all the virtual methods defined
in fragmental base classes, or in C itself. For the rest of direct or
indirect base classes that are not fragmental, the compiler tries to
minimize the number of vtable pointers in C (as usual).

Objects of type C only have one vtable pointer. Attempting to reduce
that number might prove more tricky.

Wrong. (see above)

Quote:

[snip]

3) C# like Properties using the proposed new language features.

[snipped example]

This is much more efficient than 1.1, and much easier to read than 1.2
imo.

So, the only way this could be more efficient is if it avoided virtual
function calls (and then most likely only minimally). But you haven't
explained a mechanism by which it avoids the virtual function calls.

It does. The machine code will be more or less equivalent to the CRTP
solution, that does not need virtual function calls. The main
difference to CRTP is readability. CRTP, as much as I like it, will
always be a nasty workaround.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Simon Farnsworth
Guest





PostPosted: Sun Dec 17, 2006 6:29 pm    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:

Quote:
The vtable pointer is implemented as a hidden non-static member of a
class with virtual functions. Of course, for any non-static class
member, it is not the class but the instance where this member is
stored - I thought this is clear from my explanation?

Now, if C is derived from multiple base classes B_1...B_n with virtual
methods B_1::foo_1() .. B_n::foo_n(), C needs one vtable for each of
these base classes. And instances of C store one vtable pointer for
each of these base classes. This seems strange, but if you think about
it (or just read somewhere), you will agree that it is necessary. If
you have a poiner B_i* b, the virtual function call b->foo_i() will
trigger a vtable lookup in the specific table for the part of C that is
derived from B_i.

Not in a sane compiler implementation. C has one vtable, set up such that

the vtable for (e.g.) the B interface is an offset into that vtable. Thus,
C's vtable in memory looks like:

+-+------------+
|0|C's virtuals|
+-+------------+
|b|B's virtuals|
+-+------------+
|a|A's virtuals|
+-+------------+

An instance of C need only store a pointer to the entire vtable; the
compiler is aware of the offsets a and b in the table above, and generates
the code needed to get at the different vtables at compile time (it can
refer to the B instance vtable as the C instance vtable plus offset b, for
example). Only one vtable pointer is needed, and the offsets are not needed
at runtime.
--
Simon Farnsworth

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vidar Hasfjord
Guest





PostPosted: Mon Dec 18, 2006 12:31 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:
Quote:
A primary goal of inheritance is to avoid code redundancy (that causes
more trouble than just work, btw).

Ok, if I understand correctly fragmental classes are there to *inject*
code, not to establish OOP type relationships (typical "is-a"
relationships established by inheritance). This leads me to think that
the use of inheritance is the wrong mechanism then.

It seems the problem can be solved by the concept proposal for C++0x:

template <typename T>
concept Property <P> {
typedef T value_type;

// All P must implement:
const T& P::get () const;
void P::set (const T&);

// Default operations (these are *injected*):
P& P::operator = (const T& v) {set (v); return *this;}
const T& P::operator T () {return get ();}
}

Usage:

class C {
float angle_;

public:
struct Angle {
void set (float f) {...}
float get() {...}
} angle;

concept_map <float> Property <Angle>;
};

This is a more regular method of injecting code (or formally "add an
interface" to a class). Having a third way --- fragmental classes ---
seems unnecessary.

Also, why the need for enclosing_object and offsetof tricks? It seems
to me that, in the common case at least, you can just as well just
store the implementation data in the property itself:

class C {
public:
struct Angle {
void set (float f) {...}
float get() {...}
private: float value;
friend C; // Give access to enclosing class (optional).
} angle;

concept_map <float> Property <Angle>;
};

Now implement the enclosing class in terms of (angle.value) if access
is needed, or plain (angle) to go through the Property interface as
outside clients must do.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Mon Dec 18, 2006 12:33 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

Quote:
An instance of C need only store a pointer to the entire vtable; the
compiler is aware of the offsets a and b in the table above, and generates
the code needed to get at the different vtables at compile time (it can
refer to the B instance vtable as the C instance vtable plus offset b, for
example). Only one vtable pointer is needed, and the offsets are not needed
at runtime.
--
Simon Farnsworth

So, this is what g++ does.

http://en.wikipedia.org/wiki/Virtual_function_table#Multiple_Inheritance
Here it's only about the g++ compiler.

http://www.gamedev.net/community/forums/viewreply.asp?ID=2827135
(a discussion, my nick there is "lhead")

http://www.parashift.com/c%2b%2b-faq-lite/virtual-functions.html#faq-20.4
(explanations)

Self Experiment:
Define the classes A and B with virtual functions. Then define a class
C deriving from A and B, and test the memory size of C objects. My
experience with g++ is that any (otherwise empty) base class with
virtual functions will increase the size of C, but any empty base class
without virtuals will not.

------

Now let's create an example..

struct A {
virtual void foo_A() {cout << "foo_a\n";}; // index 0 in vtable
};

struct B {
virtual void foo_B() {cout << "foo_b\n";}; // index 0 in vtable
};

struct X : A, B {
virtual void foo_A() {cout << "foo_ax\n";}
virtual void foo_B() {cout << "foo_bx\n";}
};

struct Y : A, B {
virtual void foo_A() {cout << "foo_ay\n";}
virtual void foo_B() {cout << "foo_by\n";}
};

int main() {
X x; Y y;
A* ax = x;
A* ay = y;
B* bx = x;
B* by = y;
cout << reinterpret_cast<char*>(ax) << endl;
cout << reinterpret_cast<char*>(ay) << endl;
cout << reinterpret_cast<char*>(bx) << endl; // should be different
from ax
cout << reinterpret_cast<char*>(by) << endl; // should be different
from ay
ax->foo_A();
ay->foo_A();
bx->foo_B();
by->foo_B();
}

Now, what happens in ax->foo_A() ? At this moment, we know the base
class A and the adress ax, and can read anything that is stored there.
The function call tells us that we need to look up index 0 in the
vtable. And the adress of the vtable is stored in the position where ax
points to (that is different from bx). Assuming there would be only one
vtable, we wouldn't know which function to call.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Simon Farnsworth
Guest





PostPosted: Mon Dec 18, 2006 9:01 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:

Quote:
Self Experiment:
Define the classes A and B with virtual functions. Then define a class
C deriving from A and B, and test the memory size of C objects. My
experience with g++ is that any (otherwise empty) base class with
virtual functions will increase the size of C, but any empty base class
without virtuals will not.

Let's talk through just what the code below does, because I think you'll see

*why* C only needs one vtable once you're understanding this. I've taken
the liberty of fixing the obvious typos.
Quote:
------

Now let's create an example..

struct A {
virtual void foo_A() {cout << "foo_a\n";}; // index 0 in vtable
};
A's size is one vtable entry.

struct B {
virtual void foo_B() {cout << "foo_b\n";}; // index 0 in vtable
};
B's size is also one vtable entry.

struct X : A, B {
virtual void foo_A() {cout << "foo_ax\n";}
virtual void foo_B() {cout << "foo_bx\n";}
};
X's size is two vtable entries; for simplicity, let us assume that the

vtable for A is first, then the vtable for B. The compiler knows the
following:
1. The size of the vtable for X
2. The offset of the subset of X's vtable that's equivalent to a vtable for
A; in this case, 0.
3. The offset of the subset of X's vtable that's equivalent to a vtable for
B; in this case, 1.
Quote:

struct Y : A, B {
virtual void foo_A() {cout << "foo_ay\n";}
virtual void foo_B() {cout << "foo_by\n";}
};
Similar to X, but with Xs replaced with Ys.

int main() {
X x; Y y;
x is an object of size two vtable entries, at an unknown address.
A* ax = &x;
ax is a pointer to x, adjusted for the offset of the subset of X's vtable

that's equivalent to A's vtable; in this case, it's the same as the address
of x.
Quote:
A* ay = &y;
Similar to ax, but with the X/Y substitution.
B* bx = &x;
bx is a pointer to x, adjusted for the offset of the subset of X's vtable

that's equivalent to B's vtable; in this case, it's one vtable entry higher
than x.
Quote:
B* by = &y;
Similar to bx, but with X/Y subsitution.
cout << reinterpret_cast<void*>(ax) << endl;
cout << reinterpret_cast<void*>(ay) << endl;
cout << reinterpret_cast<void*>(bx) << endl; // should be different
from ax
cout << reinterpret_cast<void*>(by) << endl; // should be different
from ay
The reason these pointer values differ is that the compiler has done the

*constant* arithmetic needed to choose the right subset of the vtable.
There's still only one vtable.
Quote:
ax->foo_A();
ay->foo_A();
bx->foo_B();
by->foo_B();
}

Now, what happens in ax->foo_A() ? At this moment, we know the base
class A and the adress ax, and can read anything that is stored there.
The function call tells us that we need to look up index 0 in the
vtable. And the adress of the vtable is stored in the position where ax
points to (that is different from bx). Assuming there would be only one
vtable, we wouldn't know which function to call.

By analogy, take the following code:


int nums[10];
int *a = &nums[1];
int *b = &nums[3];
int *c = &nums[5];
int *d = &nums[8];

How many arrays of integer do I have? If I'm understanding your argument
correctly, you would argue that I have five arrays of integer, since a, b,
c and d and nums are all not equal. However, the only array is nums; it's
got 10 elements, and I've set a, b, c and d to point to four subsets of the
array.
--
Simon Farnsworth

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Dave Harris
Guest





PostPosted: Mon Dec 18, 2006 11:04 pm    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de () wrote (abridged):
Quote:
Problems:
- Performance overhead because of vtable lookup that is not nessecary
from a technical perspective.

Given that it's not necessary, are you sure a good compiler can't just
optimise it away? In the line:

c.angle += 180; // -> c.angle_ == 135

the exact type of c.angle is known. The call to Float::operator+=() can be
inlined. We can propagate knowledge of the type of c.angle to the inlined
body, and use it to dispatch the calls to get() and set() statically.

Alternatively, as your second example shows, we can just use the CRTP.
Your 1.2 code slightly muddies the issue by mixing in a second
optimisation to avoid the enclosing_object pointer. If we drop that, the
code isn't so unclear. (In any case it seems to me that the concept of an
Angle in degrees is reusable and doesn't need to be defined in-place.
Keeping different concepts separate helps clarify the code.)

class Angle : Float<Angle> {
float &angle_;
public:
Angle( float &angle ) : angle_(angle) {
}
void set(float f) {
while(f>=360)
f -= 360;
while(f<0)
f += 360;
angle_ = f;
}
float get() {
return angle_;
}
};

class C {
float angle_;
public:
C() : angle(angle_) {
}
Angle angle;
};

Here we have no virtual functions. I don't think the code is hard to read,
given what it does. The overhead is the reference Angle::angle_. Even that
could be eliminated if we didn't need the angle_ to be shared.


Quote:
2.3) The "enclosing_object" keyword. This keyword returns a pointer to
the enclosing object. Technically, this can work in two ways:
- for member classes that are defined as "nested", the
"enclosing_object" keyword will just return the hidden reference.

I don't think this adds much benefit over using a reference manually.

I have used Java, which works a bit like that, and it just seemed to
obscure what was going on without helping me do anything new.


Quote:
- for anonymous member classes defined in the first way (2.1 [*]), the
"enclosing_object" keyword uses a mechanic that is equivalent to the
offsetof macro trick. The anonymous definition guarantees a fixed
adress difference to the enclosing object.

Although I am more sympathetic to this, it seems to be hedged around with
restrictions. The struct has to be anonymous, it can't be reusable, it
can't even be used for multiple member variables within the same class. It
all seems a bit messy and inelegant.

I think I'd rather have a more rigorous way to encapsulate the offsetof
trick. Perhaps some kind of based pointer.

-- Dave Harris, Nottingham, UK.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Tue Dec 19, 2006 3:23 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

Hmm, most of what i can do is repeating my other posts. The main issue
is replacing CRTP and offsetof with built-in syntax. So the following
questions arise:

1) Are CRTP / offsetof justified?

Is there a significant number of possible situations where using CRTP
or offsetof is justified?

Here it's not talking about my examples alone, but the general case.
Serious examples are usually complicated, but it is a known experience
they exist. If you show how CRTP is not necessary in my examples, this
does not discard it as a common and justified practice.

The offsetof question is frequently asked in forum discussions, so
obviously there is a need.

At home I am experimenting on a 'universal' data structure for
polygonal meshes of arbitrary dimension (subdivision of an n-manifold
into cells of dimension 0..n). There you have all the requirements we
are discussing here: every additional reference, every vtable pointer,
every virtual function lookup hurts.

A more common example for the offsetof stuff is the state machine in my
first post. It has only two states, but the principle allows a machine
with an arbitrary number of states (known by the programmer), and
additional shared data (like arrays, etc). Here the offsetof trick is
quite useful to avoid unnecessary references. But you will also agree
that adding a new state by copy+paste can easily lead to mistakes - the
offsetof macro needs to get exactly the name of the state, and in case
you use reference, you need to initialise all the references in the
constructor of the state machine.

2) Performance benefit of CRTP and offsetof?

Do CRTP and offsetof give us a significant performance benefit (time
and space), compared to other solutions like virtual functions, or
explicit references? I'd say yes, especially when dealing with small
classes where the vtable pointer or explicit references would lead to
50% or more increase in size. And for small functions where vtable
lookup has a significant impact on the time performance.

3) Elegance of CRTP and offsetof solutions?

Do CRTP and offsetof give us elegant solutions, are they easy to teach
and understand?

I like CRTP, but I think it is not easy to teach and understand.
Especially, if your project is bloated with templates anyway, you will
be happy to have one less. In the end, I would say CRTP is a nasty
workaround.

And a macro like offsetof is nasty and not even typesafe.

Imagine you have 10 nested objects, all with a different type (for
instance, if you decide to implement a state machine in the way I
suggested - with additional shared data that justifies using offsetof).
Now for each of these nested objects you either need to store a
reference, or re-write the offsetof trick. Now imagine you add one of
these objects - you will most likely mess that up.

4) New language feature justified?

Is it benefitial / necessary / justified to replace CRTP and offsetof
with reliable and built-in language features? I think you can guess my
answer Smile but that's the matter of discussion in this thread.

5) What is the best solution?

Is my proposal really a satisfying solution? Are there alternatives?
I'm all interested!!

6) Positive/Negative side effects of a proposed solution?

Given a proposed solution, does this solution even solve other
problems? Does it allow a new programming style?

Well, I think a language feature like fragmental classes would enable
the inexperienced programmer to create CRTP-like compile time
polymorphism architectures, and to read and understand such code
written by other people.

Libraries like STL or boost could provide fragmental classes to derive
from without too much thinking. Or do you want the general programmer
to derive from a CRTP ? Imagine the crtp has more than one template
parameter - now the client needs to find out which parameter gets the
type of the derived class.



Dave Harris wrote:
Quote:
stroumpf2004-gtalk (AT) yahoo (DOT) de () wrote (abridged):
Problems:
- Performance overhead because of vtable lookup that is not nessecary
from a technical perspective.

Given that it's not necessary, are you sure a good compiler can't just
optimise it away? In the line:

c.angle += 180; // -> c.angle_ == 135

the exact type of c.angle is known. The call to Float::operator+=() can be
inlined. We can propagate knowledge of the type of c.angle to the inlined
body, and use it to dispatch the calls to get() and set() statically.

We can optimize away the call, but not the vtable pointer. But it seems
you are right, as long as anything is inlined.

Quote:

Alternatively, as your second example shows, we can just use the CRTP.

Yes.

Quote:
Your 1.2 code slightly muddies the issue by mixing in a second
optimisation to avoid the enclosing_object pointer. If we drop that, the
code isn't so unclear.

This would mean you consider CRTP a reader-friendly solution. If we
accept that as a general statement, this kills the main argument for
fragmental classes. The only remaining benefit would be the the benefit
when deriving from multiple classes with virtual functions.

Quote:
(In any case it seems to me that the concept of an
Angle in degrees is reusable and doesn't need to be defined in-place.
Keeping different concepts separate helps clarify the code.)

class Angle : Float<Angle> {
float &angle_;
public:
Angle( float &angle ) : angle_(angle) {
}
void set(float f) {
while(f>=360)
f -= 360;
while(f<0)
f += 360;
angle_ = f;
}
float get() {
return angle_;
}
};

class C {
float angle_;
public:
C() : angle(angle_) {
}
Angle angle;
};

Here we have no virtual functions. I don't think the code is hard to read,
given what it does. The overhead is the reference Angle::angle_. Even that
could be eliminated if we didn't need the angle_ to be shared.

Well, if we don't need to share there is no need for offsetof or CRTP
anyway - no surprise. Let's instead just assume there are cases where
we want to share.

Quote:


2.3) The "enclosing_object" keyword. This keyword returns a pointer to
the enclosing object. Technically, this can work in two ways:
- for member classes that are defined as "nested", the
"enclosing_object" keyword will just return the hidden reference.

I don't think this adds much benefit over using a reference manually.

I have used Java, which works a bit like that, and it just seemed to
obscure what was going on without helping me do anything new.


Agreed, that's a matter of taste. I liked that when using Java. And I
don't see why it would be bad to have that possibility. My first idea
was this offsetof thing, but I thought once we start that, we can also
go on and provide a more general way to get the enclosing object.

Quote:

- for anonymous member classes defined in the first way (2.1 [*]), the
"enclosing_object" keyword uses a mechanic that is equivalent to the
offsetof macro trick. The anonymous definition guarantees a fixed
adress difference to the enclosing object.

Although I am more sympathetic to this, it seems to be hedged around with
restrictions. The struct has to be anonymous, it can't be reusable, it
can't even be used for multiple member variables within the same class. It
all seems a bit messy and inelegant.

Restrictions like that are necessary. If you want to use offsetof, you
need to guarantee that the nested class has only one instance, as a
member of its enclosing class. The offsetof macro, btw, does not
guarantee anything, which can likely lead to errors.

If you want to reuse the struct, you need to create subclasses for each
occurance - or you can't use an offsetof-like mechanism.

Quote:

I think I'd rather have a more rigorous way to encapsulate the offsetof
trick. Perhaps some kind of based pointer.

Well, I am happy for any kind of suggestions. The condition is that
your proposal still allows my big state machine example!!

{ Quoted signature and clc++m banner removed. -mod }

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vidar Hasfjord
Guest





PostPosted: Wed Dec 20, 2006 12:05 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:
Quote:
Thank you for reading everything!

No need to thank me. I do find part of the proposal interesting, and
you obviously put a lot of heart into it.

Quote:
It seems like "code injection" is a good description of what I'm trying
to do. But this doesn't mean that there is no "is-a" relationship. As I
said, the mechanism does almost the same as CRTP, so most arguments
against my proposal would also bury CRTP.

No, that's not a logical deduction. The other possibility is that you
do not put forward a convincing argument that CRTP is bad and that a
replacement is needed. You argue that CRTP is a nasty workaround, that
"the code is not that nice to read" and "we don't like to depend on
CRTP [...] for an everyday problem". These arguments have only
subjective merit.

Of course, we wouldn't want to program virtual functions in C, hence
the virtual function feature in C++. Having the feature in the language
in this case, promotes and simplifies OOP - a programming paradigm.

In the case of your proposed fragmental classes, I personally don't see
the justification in increasing the complexity of the language by
adding what seems a special purpose feature; a feature that the
language --- so awe-inspiring and elegantly --- is already able to
express in terms of CRTP. The readability improvement of fragmental
classes that you claim is not worth the added complexity to the
language in my view.

CRTP is not obvious, but it's an idiom that is easily learned and which
makes you respect the expressivity of the language. I don't find
fragmental classes any more obvious, and I imagine it would just push
the (novice) programmer into the language documentation to explain what
goes on behind the scenes.

Quote:
However, as I understand it, concepts can't add data elements to a
class - right? So how would you implement a general CRTP example with
concept_map?

I wouldn't need to. I would use CRTP.

I would use concepts in the cases where I needed to retrofit an
existing class with extra interfaces and default behaviour (injected
code). Adding a Property interface to a class in this manner seems like
an elegant solution.

Quote:
- CalculatorEngine*, CalculatorEngine& and CalculatorEngine will never
be used as types (except as a base class).

That again enforces my view that inheritance is the wrong solution. The
language just becomes more complex when inheritance has more meanings.

Quote:
[need for enclosing_object]
Now it's a question of finding a good example. At home I frequently
wish to have direct access to the enclosing object - and people in
forums frequently ask for the same.

Yes, after pressing the send button I recalled that I've actually read
one or more articles about the offsetof hack to implement properties. I
was just side-tracked by the fact that your example did not demonstrate
the need.

In fact I find this part of your proposal interesting, and I agree that
a mechanism with language guarantees is necessary. That said, so far I
find your proposed solution for inner classes too complex and
intertwined with the fragmental class proposal.

As I see it, a solution has the following requirements:

- a guaranteed (portable) mechanism to return the pointer to the
enclosing object given the pointer to an embedded object,
- restrictions ensuring the mechanism only is applicable to truly
embedded objects.

I propose a slightly simpler scheme than yours, in which an embedded
object class is tagged by "embedded". This only allows the type to be
used to declare embedded members. Other usages are forbidden. An
embedded class has access rights to the enclosing class. The
"enclosing_object" keyword is replaced by "C::this" where C is the
enclosing class. The latter avoids adding another keyword. It also
nicely extends to allow the shortcut "C::member" for "C::this->member",
and even to transparent lookup in the namespace of the enclosing class
(i.e. simply "member"). For example:

class C {
float angle_; // Angle in degrees.

public:
embedded struct AngleDeg {
void set (float f) {C::angle_ = ...}
float get () const {return angle_;}
} angle_deg;

embedded struct AngleRad {
void set (float f) {...}
float get () const {...}
} angle_rad;

concept_map <float> Property <AngleDeg>;
concept_map <float> Property <AngleRad>;
};

C::AngleDeg d; // Error: Cannot exist outside C.

You could use CRTP instead of concepts to inject the property
interface/code, but using concepts has the added benefit that
properties can be used in constrained (i.e. type-checked) generic code:

template <Property P>
void foo (P& p) {...}

Quote:
I think it's a hole in the language to hide an obvious information from
the programmer, and instead make him depend on nasty macros or
technically redundant references.

I agree. The ability to access the enclosed object from an embedded
object should be a proper feature of C++.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vidar Hasfjord
Guest





PostPosted: Wed Dec 20, 2006 12:07 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de wrote:
Quote:
[...]
Restrictions like that are necessary. If you want to use offsetof, you
need to guarantee that the nested class has only one instance,

That's not entirely correct. If the embedded class is self-contained,
then you can instantiate as many members as you want. For example
(using my simpler proposal; see my other reply):

class C {
void update ();

public:
embedded struct ColorProperty {
void set (Color c) {color = c; update ();}
Color get () const {return color;}
protected: Color color;
};

ColorProperty foreground_color;
ColorProperty background_color;

concept_map <Color> Property <ColorProperty>;
};

If each instance of the embedded class need to bind to different
members of the enclosing class, you can parameterize the embedded
class. For example:

class C {
Color f_color;
Color b_color;
void update ();

public:
template <Color C::* cmem>
embedded struct ColorProperty {
void set (Color c) {C::*cmem = c; update ();}
Color get () const {return C::*cmem;}
};

ColorProperty <&f_color> foreground_color;
ColorProperty <&b_color> background_color;

template <Color C::* cmem>
concept_map <Color> Property <ColorProperty <cmem>>;
};

You could even make it more reusable:

// Library:

template <Updatable C, Color C::* cmem>
embedded struct ColorProperty {
void set (Color c) {C::*cmem = c; C::update ();}
Color get () const {return C::*cmem;}
};

template <Updatable C, Color C::* cmem>
concept_map <Color> Property <ColorProperty <cmem>>;

// Usage:

class C {
Color f_color;
Color b_color;
void update ();

public:
ColorProperty <&f_color> foreground_color;
ColorProperty <&b_color> background_color;
};

concept_map Updatable <C>;

The self-contained color properties allows an even simpler library
solution in the context of this example:

// Library:

template <Updatable C>
embedded struct ColorProperty {
void set (Color c) {color = c; C::update ();}
Color get () const {return color;}
protected: Color color;
};

template <Updatable C>
concept_map <Color> Property <ColorProperty>;

// Usage:

class C {
void update ();
public:
ColorProperty <C> foreground_color;
ColorProperty <C> background_color;
};

concept_map Updatable <C>;

Although I've used properties as examples here, note that the mechanism
generalizes to any possible use of embedded classes.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Dave Harris
Guest





PostPosted: Wed Dec 20, 2006 3:47 am    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

stroumpf2004-gtalk (AT) yahoo (DOT) de () wrote (abridged):
Quote:
We can optimize away the call, but not the vtable pointer.

sizeof(C::angle) is going to be greater than 0 regardless so some overhead
is unavoidable.


Quote:
This would mean you consider CRTP a reader-friendly solution.

Indeed.


Quote:
If you want to reuse the struct, you need to create subclasses for each
occurance - or you can't use an offsetof-like mechanism.

You can make a generic template which takes the offset as an argument.
Like:

template <int offset>
class OffsetFloat {
float &value() {
return (float *) ((char *)this+offset);
}
public:
float get() { return value(); }
void set( float f ) { value() = f; }
};

class C {
float angle_;
float angle2_;
public:
OffsetFloat<offsetof(C,angle_) - offsetof(C,angle)> angle;
OffsetFloat<offsetof(C,angle2_) - offsetof(C,angle2)> angle2;
};

I agree it would be good to lose the offsetof hack, but I'd rather not
sacrifice reusability.


Quote:
The offsetof macro, btw, does not guarantee anything, which can
likely lead to errors.

Yes, that's part of why I said I was more sympathetic to this part of the
proposal.

-- Dave Harris, Nottingham, UK.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Wed Dec 20, 2006 7:50 pm    Post subject: Re: C# Properties, inner classes and CRTP Reply with quote

Vidar Hasfjord wrote:
Quote:
It seems like "code injection" is a good description of what I'm trying
to do. But this doesn't mean that there is no "is-a" relationship. As I
said, the mechanism does almost the same as CRTP, so most arguments
against my proposal would also bury CRTP.

No, that's not a logical deduction. The other possibility is that you
do not put forward a convincing argument that CRTP is bad and that a
replacement is needed. You argue that CRTP is a nasty workaround, that
"the code is not that nice to read" and "we don't like to depend on
CRTP [...] for an everyday problem". These arguments have only
subjective merit.

Of course, we wouldn't want to program virtual functions in C, hence
the virtual function feature in C++. Having the feature in the language
in this case, promotes and simplifies OOP - a programming paradigm.

In the case of your proposed fragmental classes, I personally don't see
the justification in increasing the complexity of the language by
adding what seems a special purpose feature; a feature that the
language --- so awe-inspiring and elegantly --- is already able to
express in terms of CRTP. The readability improvement of fragmental
classes that you claim is not worth the added complexity to the
language in my view.

CRTP is not obvious, but it's an idiom that is easily learned and which
makes you respect the expressivity of the language. I don't find
fragmental classes any more obvious, and I imagine it would just push
the (novice) programmer into the language documentation to explain what
goes on behind the scenes.

Well, let's agree on this point for now.

But how would you "inject" a number of virtual functions into your
class? Imagine your class gets a tuple of types as a template
parameter. Now for each of these types T1...Tn you want a method
"virtual foo(T1)". virtual functions can't have template parameters, so
it seems the only way to inject these versions of foo is inheritance.
You would define n different helper classes H1...Hn (as a template),
each defining one of the virtual functions, and then derive from these
using some template metaprogramming. To avoid a bloat of the vtable
pointers, you need to use serial inheritance (You would define the
helper classes as parameterized mixins). Doing this is not only a
mind-bending job, it also bloats your error messages. Parallel
inheritance seems more natural, if it is only to inject independent
functions. If you had a way to tell the compiler that H1...Hn are just
helper classes (that are not used as types), it could do with one,
instead of n vtable pointers.

Quote:
- CalculatorEngine*, CalculatorEngine& and CalculatorEngine will never
be used as types (except as a base class).

That again enforces my view that inheritance is the wrong solution. The
language just becomes more complex when inheritance has more meanings.

Ok, what is your solution?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.