 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Marco Jez Guest
|
Posted: Mon Sep 19, 2005 5:15 pm Post subject: problem with template recursion |
|
|
I've already posted this question to clc++ but it wasn't helpful, so I'm
trying here.
I'm rewriting an introspection library I wrote some time ago, introducing
new features and improving consistency between the run-time rules provided
by the library (name lookup, type conversions, cv qualifiers, etc.) and
those provided at compile time by the C++ language.
In the library core lies a class named "object" whose purpose is to act as a
container for objects of any type. It works pretty much like boost::any,
although it differs slightly in the semantics (but that's not relevant to my
question). This is an example of how this class is supposed to be used:
// x contains a const char*
object x = "hello, world";
int n = 10;
// y contains an int
object y = n;
// z contains an int*
object z = &n;
Pretty straightforward, no problems up to here. Class "object" is roughly
defined as follows (many details omitted for clarity):
class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)) {}
protected:
struct instance_base
{
virtual ~instance_base() {}
};
template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
};
private:
instance_base* _inst;
};
Now I want to give the user the ability to create new objects (that is, new
instances of class "object") by either creating pointers to or dereferencing
existing ones. An example should clarify what I mean:
// x holds an int
object x = 10;
// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance<int*>
object y = make_pointer(x);
// ideally, z should hold the same value as x
object z = dereference(y);
My first attempt to implement this behaviour was to add a virtual method to
object::instance_base:
struct instance_base
{
...
virtual instance_base* mkptr() = 0;
...
};
and its concrete implementation in object::instance<T>:
template<typename T>
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance<T*>(&_val); }
...
};
The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.
So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?
Cheers,
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Przemyslaw Szymanski Guest
|
Posted: Tue Sep 20, 2005 11:19 am Post subject: Re: problem with template recursion |
|
|
Marco Jez wrote:
[...]
| Quote: | template<typename T
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance
...
};
The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.
So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?
|
Hello,
You need to define a partial specialization of object::instance for T*:
template <typename T>
struct instance<T*> : public instance_base
{
instance(const T* val): _val(val) {}
instance_base* mkptr() { return new instance<T*>(_val); }
//the following would cause infinite recursion too
//instance_base* mkptr() { return new instance<T**> (&_val); }
T* _val;
};
Przemek.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
ylegoc Guest
|
Posted: Tue Sep 20, 2005 11:21 am Post subject: Re: problem with template recursion |
|
|
Marco Jez a écrit :
| Quote: | I've already posted this question to clc++ but it wasn't helpful, so I'm
trying here.
I'm rewriting an introspection library I wrote some time ago, introducing
new features and improving consistency between the run-time rules provided
by the library (name lookup, type conversions, cv qualifiers, etc.) and
those provided at compile time by the C++ language.
In the library core lies a class named "object" whose purpose is to act as a
container for objects of any type. It works pretty much like boost::any,
although it differs slightly in the semantics (but that's not relevant to my
question). This is an example of how this class is supposed to be used:
// x contains a const char*
object x = "hello, world";
int n = 10;
// y contains an int
object y = n;
// z contains an int*
object z = &n;
Pretty straightforward, no problems up to here. Class "object" is roughly
defined as follows (many details omitted for clarity):
class object
{
public:
template<typename T
object(const T &v): _inst(new instance
protected:
struct instance_base
{
virtual ~instance_base() {}
};
template<typename T
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
};
private:
instance_base* _inst;
};
Now I want to give the user the ability to create new objects (that is, new
instances of class "object") by either creating pointers to or dereferencing
existing ones. An example should clarify what I mean:
// x holds an int
object x = 10;
// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance
object y = make_pointer(x);
// ideally, z should hold the same value as x
object z = dereference(y);
My first attempt to implement this behaviour was to add a virtual method to
object::instance_base:
struct instance_base
{
...
virtual instance_base* mkptr() = 0;
...
};
and its concrete implementation in object::instance
template<typename T
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance
...
};
The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.
So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?
Cheers,
Marco
|
Here is my solution:
The problem is that we cannot call the object constructor in the
following line:
object y = make_pointer(x);
since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.
Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.
Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.
implementation:
class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)) {}
// copy constructor
object(const object & obj): _inst(obj._inst->clone()) {}
// address-of operator
object operator& () const
{
// call to constructor from instance_base *
return object(_inst->make_pointer());
}
// dereference operator
object operator* () const
{
...
}
// don't forget destructor
~object()
{
delete _inst;
}
protected:
struct instance_base
{
virtual ~instance_base() {}
// added method
virtual instance_base * clone() const;
virtual instance_base * make_pointer() const;
};
template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
virtual instance_base * clone() const {...}
virtual instance_base * make_pointer() const {...}
};
private:
// constructor from instance_base *
object(instance_base * inst) : _inst(inst) {}
instance_base* _inst;
};
You can use it as follows:
object x(10);
object y(&x);
object z(*y);
The code is not complete, but I hope this helps you.
Yannick Le Goc
Software engineer at ObjetDirect
France
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Marco Jez Guest
|
Posted: Tue Sep 20, 2005 1:56 pm Post subject: Re: problem with template recursion |
|
|
| Quote: | since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.
Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.
Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.
|
Thanks but this doesn't solve my problem: what to put in
instance<>::make_pointer() ?
Whether I use overloaded operators or other methods to call
instance::make_pointer(), and whether I set the _inst member from an
external friend function or in an initialization constructor, it really
doesn't make any difference. instance<T>::make_pointer() will always need to
create an instance<T*> in order to create the actual pointer, and this
causes a compile-time recursion that I can't get rid of :-/
Cheers,
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Marco Jez Guest
|
Posted: Tue Sep 20, 2005 1:56 pm Post subject: Re: problem with template recursion |
|
|
| Quote: | template <typename T
struct instance
{
instance(const T* val): _val(val) {}
instance_base* mkptr() { return new instance<T*>(_val); }
//the following would cause infinite recursion too
//instance_base* mkptr() { return new instance<T**> (&_val); }
T* _val;
};
|
This wouldn't allow recursive pointers, that is:
object x = make_pointer(make_pointer(make_pointer(y)));
Unfortunately I can't limit the usage of make_pointer() to a single level of
indirection.
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Zhen Yao Guest
|
Posted: Wed Sep 21, 2005 9:05 am Post subject: Re: problem with template recursion |
|
|
Then what about restricting the level of indirections to a certain
limit?
template <typename T>
struct instance<T****************************> : instance_base
{
typedef T**************************** value_type;
instance(const value_type& val) : _val(val) {}
instance_base* mkptr()
{
assert(0);
return 0;
}
value_type _val;
};
By using some preprocessor magic, the maximum level of indirections can
also be defined using a preprocessor macro.
Is this workaround acceptable for you?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Wed Sep 21, 2005 9:07 am Post subject: Re: problem with template recursion |
|
|
Marco Jez wrote:
| Quote: | since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.
Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.
Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.
Thanks but this doesn't solve my problem: what to put in
instance<>::make_pointer() ?
Whether I use overloaded operators or other methods to call
instance::make_pointer(), and whether I set the _inst member from an
external friend function or in an initialization constructor, it really
doesn't make any difference. instance<T>::make_pointer() will always need to
create an instance<T*> in order to create the actual pointer, and this
causes a compile-time recursion that I can't get rid of :-/
Cheers,
Marco
|
The infinite recursion stems from the fact that object<T>::make_ptr
instantiates and returns an object<T*> whose own make_ptr method
instantiates and returns an object<T**> which in turn - well I don't
have the patience to type the entire sequence out. But suffice it to
say this pattern goes on for a while, if not longer.
The simplest solution would be to declare make_ptr a standalone
function template. To do so, I would first make object the template
class. As currently implemented, the type used to construct an object
object [sic] is not retained. A holder of such an object has no way of
determining the type it holds. Such a loss of type information
nullifies one of the primary benefits of using templates. To put it
another way, without the type information, object may as well be
holding void *.
So let's assume object is a class template implemented along these
lines for type T:
template <typename T>
struct object
{
object( T& t) : t_(t) {}
T* get_ptr() const
{
return &t_;
}
private:
T& t_;
};
We will also need a specialization of object when T is a pointer type
(which would include pointer-to-pointer types):
template <typename T>
struct object<T*>
{
object( T* t) : t_(t) {}
T** get_ptr() { return &t_; }
private:
T* t_;
};
Finally, we just need a standalone make_ptr routine to return an
object<T*> for an object<T>:
template <typename T>
object<T*>
make_ptr( object<T>& inObject)
{
return object<T*>( inObject. get_ptr() ):
}
As a standalone function template make_ptr is instantiated only from
calls to it that appear in the source code - of which there can be only
a finite number Furthermore since make_ptr does not call itself either
diretly or indirectly, there is no infinite recursion.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Marco Jez Guest
|
Posted: Wed Sep 21, 2005 11:53 am Post subject: Re: problem with template recursion |
|
|
"Zhen Yao" <allen.yao (AT) gmail (DOT) com> ha scritto nel messaggio
news:1127269404.428095.54100 (AT) g14g2000cwa (DOT) googlegroups.com...
| Quote: | Then what about restricting the level of indirections to a certain
limit?
|
This will certainly be my final solution unless I find a better one soon. I
was just hoping there was a clean way to do that without imposing any
restrictions... :-/
Thanks,
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Marco Jez Guest
|
Posted: Wed Sep 21, 2005 11:54 am Post subject: Re: problem with template recursion |
|
|
| Quote: | The simplest solution would be to declare make_ptr a standalone
function template. To do so, I would first make object the template
class. As currently implemented, the type used to construct an object
object [sic] is not retained. A holder of such an object has no way of
determining the type it holds. Such a loss of type information
nullifies one of the primary benefits of using templates. To put it
another way, without the type information, object may as well be
holding void *.
|
Actually, making object a template would nullify the purpose of class object
itself: hiding the underlying instance's type at compile time, while making
it accessible at run time (as boost::any does). As I stated in my first
post, I'm writing an introspection/reflection library, so everything
revolves around this compile-time to run-time promotion. Please note that an
introspection library does NOT aim to bypass C++'s strong-typed nature for
doing the same tasks that could be done much more efficiently at compile
time through templates, instead it aims to:
- provide better run-time type information than standard RTTI;
- provide the means for accessing objects, calling functions, etc. without
needing compile-time knowledge of data types and function signatures by
providing the necessary abstractions (like the class being described here).
This feature is meant to be used mainly for interfacing C++ programs with
scripting languages, serializing objects and, more generally, for providing
out-of-the-box run-time access to any C++ object and function under the same
abstract interface.
Cheers,
Marco
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Graeme Prentice Guest
|
Posted: Thu Sep 22, 2005 2:38 pm Post subject: Re: problem with template recursion |
|
|
On 19 Sep 2005 13:15:30 -0400, Marco Jez wrote:
[snip]
| Quote: | // x holds an int
object x = 10;
// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance<int*
|
but the type of y::_inst is always pointer to instance_base, so I guess
you mean the type of the object y::_inst points at
| Quote: | object y = make_pointer(x);
// ideally, z should hold the same value as x
object z = dereference(y);
|
One possibility that *might* work is to store an extra pointer in the
object object (sic again!) - this is a pointer to a function that knows
how to create instance
you also have to change _mf.
I attempted to move this extra pointer into the heap object but didn't
solve the recursion problem so far.
class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)),
_mf(&mkptr<T>) {}
protected:
struct instance_base
{
virtual ~instance_base() {}
virtual void* get_address() = 0;
};
template<typename T>
static instance_base * mkptr(instance_base * bp)
{
return new instance<T*>((T*)bp->get_address());
}
template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
void* get_address() { return &_val; }
//instance_base* mkptr() {} return new instance<T*>(&_val); }
};
private:
instance_base* _inst;
typedef instance_base * (*mf)(instance_base *);
mf _mf;
};
int main()
{
object x = 10;
}
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Graeme Prentice Guest
|
Posted: Fri Sep 23, 2005 2:28 pm Post subject: Re: problem with template recursion |
|
|
On 22 Sep 2005 10:38:57 -0400, Graeme Prentice wrote:
| Quote: |
One possibility that *might* work is to store an extra pointer in the
object object (sic again!) - this is a pointer to a function that knows
how to create instance<T*> objects. If you change the value of _inst,
you also have to change _mf.
|
Well, except that not long after posting this I realised that this
doesn't solve the recursion problem at all, which can probably only be
solved by setting a recursion max depth with specializations.
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
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
|
|