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 

Cross-TU type --> integral id mapping

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





PostPosted: Wed Aug 17, 2005 8:56 am    Post subject: Cross-TU type --> integral id mapping Reply with quote



Hi there

I'm trying to find a portable scheme to automatically associate a type
with an id that is unique across translation units *and* does not suffer
from order of initialization problems. I believe the best approach is
probably the following, which goes back to an idea that Andrei
Alexandrescu posted in this group back in 1999 (see
[url]http://tinyurl.com/9h2qs):[/url]

#include <boost/cstdint.hpp>
#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT( sizeof( bool * ) <= sizeof( boost::uintmax_t ) );

template< class T >
struct id_holder
{
static bool dummy;
static boost::uintmax_t id;
};

template< class T >
bool id_holder< T >::dummy;
// According to 5.2.10/4 & 5.2.10/5 reinterpret_casting a pointer to a
large
// enough integral type and back must yield the original pointer. This
implies
// an unambiguous mapping pointer --> integral type object.
template< class T >
boost::uintmax_t id_holder< T >::id =
reinterpret_cast< boost::uintmax_t >( &id_holder< T >::dummy );

template< typename T >
boost::uintmax_t id()
{
return id_holder< T >::id;
}

int main()
{
std::cout << id< int >() << "n";
std::cout << id< long >() << "n";
std::cout << id< char >() << "n";
std::cout << id< void * >() << "n";
std::cout << id< void (*)() >() << "n";
std::cout << id< char ** >() << "n";
return 0;
}

This works as expected, the above program prints all different ids when
compiled with MSVC7.1 as well as GCC. So far so good. Now, AFAICT, the
expression reinterpret_cast< boost::uintmax_t >( &id_holder< T
Quote:
::dummy ) qualifies as a constant expression according to 5.19/2 &
5.19/4. The initialization of id_holder< T >::id thus qualifies as

"static initialization" (3.6.2/1) and must therefore take place before
any dynamic initialization.

My question is: Is my reading of the standard correct in that it
guarantees that the type --> id mapping scheme above will never have any
order of initialization problems (frequently encountered when functions
are involved in the initialization)? In other words, can the id()
function be used to initialize other non-local static objects without
any problems?

Thanks,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


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


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Wed Aug 17, 2005 12:44 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote



Hi Andreas,

If you compile your program into assembly, you'll probably see it
evaluating the reintrepret_cast<> code and assigning ids at run-time.
I found g++ 4.0.1 code does so on Solaris.

(gdb) run
Starting program: /export/home/fox/delroya/dev/test/clcm/typenum

Breakpoint 1, __static_initialization_and_destruction_0
(__initialize_p=1,
__priority=65535) at typenum.cc:15
15 uint64_t id_holder<T>::id =
(gdb) list
10
11 template <class T>
12 bool id_holder<T>::dummy;
13
14 template <class T>
15 uint64_t id_holder<T>::id =
16 reinterpret_cast<uint64_t>(&id_holder<T>::dummy);
17

IIUC (which is a significant qualifier in this case), the
__static_initialization_and_dsutrction_0 function performs the dynamic
initialisation of statics, and statics in other translation units might
find the ids uninitialised....

Regards, Tony


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

Back to top
Ulrich Eckhardt
Guest





PostPosted: Wed Aug 17, 2005 12:46 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote



Andreas Huber wrote:
Quote:
template< class T
struct id_holder
{
static bool dummy;
static boost::uintmax_t id;
};

template< class T
bool id_holder< T >::dummy;
// According to 5.2.10/4 & 5.2.10/5 reinterpret_casting a
// pointer to a large enough integral type and back must
// yield the original pointer. This implies
// an unambiguous mapping pointer --> integral type object.
template< class T
boost::uintmax_t id_holder< T >::id =
reinterpret_cast< boost::uintmax_t >( &id_holder< T >::dummy );

template< typename T
boost::uintmax_t id()
{
return id_holder< T >::id;
}

When I see this, I wonder why not take the address itself as ID?

typedef void* id_type;

template<typename T>
id_type id()
{
static int dummy;
return &dummy;
}

Even if there were initialisation order problems there is nothing to init
here, and the address will be created at program startup, right?

Quote:
std::cout << id< int >() << "n";
std::cout << id< long >() << "n";
std::cout << id< char >() << "n";
std::cout << id< void * >() << "n";
std::cout << id< void (*)() >() << "n";
std::cout << id< char ** >() << "n";

Should work the same, but doesn't suffer from the fact that boost::uintmax_t
doesn't necessarily have an IOStream inserter (requires a standard
extension under LLP64 architectures (e.g. win64, sigh) because there,
sizeof (long)==4 or in cases where long=32bit but a 64bit int exists and is
referenced by boost::uintmax_t).

Quote:
My question is: Is my reading of the standard correct in that it
guarantees that the type --> id mapping scheme above will never have any
order of initialization problems (frequently encountered when functions
are involved in the initialization)? In other words, can the id()
function be used to initialize other non-local static objects without
any problems?

I think converting the address of a unique object to an ID on demand is much
safer and performs the same when the ID-type is an address type.

I don't think it qualifies as (integral) constant expression though, making
it unusable as e.g. case label or for metaprogramming. You mentioned that
aspect but not that it was important to you.

Uli


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


Back to top
Anthony Williams
Guest





PostPosted: Wed Aug 17, 2005 12:59 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

"Andreas Huber" <ahd6974-spamgroupstrap (AT) yahoo (DOT) com> writes:

Quote:
I'm trying to find a portable scheme to automatically associate a type
with an id that is unique across translation units *and* does not suffer
from order of initialization problems. I believe the best approach is
probably the following, which goes back to an idea that Andrei
Alexandrescu posted in this group back in 1999 (see
[url]http://tinyurl.com/9h2qs):[/url]

#include <boost/cstdint.hpp
#include
BOOST_STATIC_ASSERT( sizeof( bool * ) <= sizeof( boost::uintmax_t ) );

template< class T
struct id_holder
{
static bool dummy;
static boost::uintmax_t id;
};

template< class T
bool id_holder< T >::dummy;
// According to 5.2.10/4 & 5.2.10/5 reinterpret_casting a pointer to a
large
// enough integral type and back must yield the original pointer. This
implies
// an unambiguous mapping pointer --> integral type object.
template< class T
boost::uintmax_t id_holder< T >::id =
reinterpret_cast< boost::uintmax_t >( &id_holder< T >::dummy );

template< typename T
boost::uintmax_t id()
{
return id_holder< T >::id;
}

Now, AFAICT, the
expression reinterpret_cast< boost::uintmax_t >( &id_holder< T
::dummy ) qualifies as a constant expression according to 5.19/2 &
5.19/4. The initialization of id_holder< T >::id thus qualifies as
"static initialization" (3.6.2/1) and must therefore take place before
any dynamic initialization.

My question is: Is my reading of the standard correct in that it
guarantees that the type --> id mapping scheme above will never have any
order of initialization problems (frequently encountered when functions
are involved in the initialization)? In other words, can the id()
function be used to initialize other non-local static objects without
any problems?

Hmm. My instinct is "yes", but 5.19/4 (address constant expressions) only
permits "pointer casts". Does a reinterpret_cast of a pointer to an integral
type count as a pointer cast? My gut feel says "no" here, as "pointer cast" is
not defined by the standard, and it seems logical to me for it to mean casting
one pointer type to another, rather than a pointer to an integer. Such an
interpretation would mean that this is *not* a constant expression.

That said, if you intend everyone to use the id() function, rather than the
value of id_holder<T>::id, why not just put this expression within the id()
function, and do away with the id_holder<T>::id member completely? That way,
the issue of initialization order is avoided completely.

OTOH, if you believe that the initializer for the id_holder<T>::id *is* a
constant expression, then you can do away with the dummy member, and use the
address of the id member itself for the initializer --- there's no point
having extra members cluttering things up to confuse people.

Anthony
--
Anthony Williams
Software Developer

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


Back to top
Andreas Huber
Guest





PostPosted: Wed Aug 17, 2005 5:17 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Hi Ulrich

Ulrich Eckhardt wrote:
Quote:
Andreas Huber wrote:
template< class T
struct id_holder
{
static bool dummy;
static boost::uintmax_t id;
};

template< class T
bool id_holder< T >::dummy;
// According to 5.2.10/4 & 5.2.10/5 reinterpret_casting a
// pointer to a large enough integral type and back must
// yield the original pointer. This implies
// an unambiguous mapping pointer --> integral type object.
template< class T
boost::uintmax_t id_holder< T >::id =
reinterpret_cast< boost::uintmax_t >( &id_holder< T >::dummy );

template< typename T
boost::uintmax_t id()
{
return id_holder< T >::id;
}

When I see this, I wonder why not take the address itself as ID?

I guess I dumbed down the example too much. I'm currently evaluating
multiple possibilities how the id's can be used to create a lookup
table. One possibility would be to use preprocessor magic (BOOST_PP) to
*calculate* a perfect hash over all ids and fill the results into an
appropriately sized array. Since the size of the array as well as the
number of types involved in the calculation are all known at compile
time, it might be possible to use constant expressions and static
initialization for all array elements.

Quote:
My question is: Is my reading of the standard correct in that it
guarantees that the type --> id mapping scheme above will never have any
order of initialization problems (frequently encountered when functions
are involved in the initialization)? In other words, can the id()
function be used to initialize other non-local static objects without
any problems?

I think converting the address of a unique object to an ID on demand is much
safer and performs the same when the ID-type is an address type.

Right, but that would leave me with dynamic initialization for all the
array elements, which is something I'd really like to avoid.

Quote:
I don't think it qualifies as (integral) constant expression though, making
it unusable as e.g. case label or for metaprogramming.

As I interpret the standard it seems there are two different kinds of
constant expressions, the ones that can be used for metaprogramming and
static initialization (5.19/1) and the ones that can be used for static
initialization only (5.19/2-5).

Quote:
You mentioned that
aspect but not that it was important to you.

If I had my way I'd want to do this (the calculation of the perfect
hash, etc.) at compile time but I don't think that is possible: The
reinterpret_cast seems to qualify as an expression that cannot be
evaluated at compile-time.

Thanks & Regards,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


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


Back to top
Andreas Huber
Guest





PostPosted: Wed Aug 17, 2005 11:14 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Anthony Williams wrote:
Quote:
"Andreas Huber" <ahd6974-spamgroupstrap (AT) yahoo (DOT) com> writes:
My question is: Is my reading of the standard correct in that it
guarantees that the type --> id mapping scheme above will never have
any order of initialization problems (frequently encountered when
functions are involved in the initialization)? In other words, can
the id() function be used to initialize other non-local static
objects without any problems?

Hmm. My instinct is "yes", but 5.19/4 (address constant expressions)
only permits "pointer casts". Does a reinterpret_cast of a pointer to
an integral type count as a pointer cast?

I was wondering about that myself...

Quote:
My gut feel says "no" here,
as "pointer cast" is not defined by the standard, and it seems
logical to me for it to mean casting one pointer type to another,
rather than a pointer to an integer. Such an interpretation would
mean that this is *not* a constant expression.

I came to a different conclusion simply because I couldn't see any
differences implementation-wise between a pointer-cast and a
reinterpret_cast. In the presence of MI a pointer-cast even seems to do
more than a reinterpret_cast.

Quote:
That said, if you intend everyone to use the id() function, rather
than the value of id_holder<T>::id, why not just put this expression
within the id() function, and do away with the id_holder<T>::id
member completely? That way, the issue of initialization order is
avoided completely.

Right, the example was dumbed down too much, please see my answer to
Ulrich.

Quote:
OTOH, if you believe that the initializer for the id_holder<T>::id
*is* a constant expression, then you can do away with the dummy
member, and use the address of the id member itself for the
initializer --- there's no point having extra members cluttering
things up to confuse people.

I guess you're right. Haven't thought about that...

Thanks & Regards,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


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


Back to top
Andreas Huber
Guest





PostPosted: Wed Aug 17, 2005 11:14 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Hi Tony

Quote:
If you compile your program into assembly, you'll probably see it
evaluating the reintrepret_cast<> code and assigning ids at run-time.
I found g++ 4.0.1 code does so on Solaris.

That's interesting. I'll see what my platform does...

Quote:
(gdb) run
Starting program: /export/home/fox/delroya/dev/test/clcm/typenum

Breakpoint 1, __static_initialization_and_destruction_0
(__initialize_p=1,
__priority=65535) at typenum.cc:15
15 uint64_t id_holder<T>::id =
(gdb) list
10
11 template <class T
12 bool id_holder 13
14 template <class T
15 uint64_t id_holder 16 reinterpret_cast<uint64_t>(&id_holder<T>::dummy);
17

IIUC (which is a significant qualifier in this case), the
__static_initialization_and_dsutrction_0 function performs the dynamic
initialisation of statics, and statics in other translation units
might find the ids uninitialised....

I'm not sure. Since the standard explicitly distinguishes between static
initialization and dynamic initialization I *think* this is evidence
supporting my interpretation. It would be interesting to see the name of
the function that GCC uses to initialize static objects with non-trivial
constructors (which would qualify as dynamic initialization).

Thanks & Regards,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


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


Back to top
glenlow@pixelglow.com
Guest





PostPosted: Thu Aug 18, 2005 1:13 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Are the static data members guaranteed to be unique between translation
units? What if the id's (and hence the point of template instantiation)
is different between translation units?

I seem to recall some work Dewhurst did with Godel numbers as a rough
typeof implementation. Each basic type was given a number, then each
way of composing the type (array, structure, pointer etc.) composed
from the basic numbers. It's basically a counting problem, albeit an
ugly counting problem.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com


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

Back to top
Andreas Huber
Guest





PostPosted: Fri Aug 19, 2005 2:28 pm    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Hi Glen

[email]glenlow (AT) pixelglow (DOT) com[/email] wrote:
Quote:
Are the static data members guaranteed to be unique between
translation units?

Yes, as long as you *statically* link all TUs into the same executable.
The linker removes duplicate template instantiations. When you link some
TUs into a dll and some into and exe and then load the dll into the
process running the exe then you need to give the linker additional
information. On Windows you do this with __declspec(dllexport) and
__declspec(dllimport)...

Quote:
What if the id's (and hence the point of template
instantiation) is different between translation units?

IME that only happens if you don't use the __declspec stuff in the
exe/dll scenario outlined above.

Quote:
I seem to recall some work Dewhurst did with Godel numbers as a rough
typeof implementation. Each basic type was given a number, then each
way of composing the type (array, structure, pointer etc.) composed
from the basic numbers. It's basically a counting problem, albeit an
ugly counting problem.

I remember having read that article. The only thing I recall is that you
have to explicitly register custom types, which I'm trying to avoid...

Thanks & Regards,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


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


Back to top
glenlow@pixelglow.com
Guest





PostPosted: Sat Aug 20, 2005 10:29 am    Post subject: Re: Cross-TU type --> integral id mapping Reply with quote

Quote:
Yes, as long as you *statically* link all TUs into the same executable.
The linker removes duplicate template instantiations.

I was thinking that, seeing that invoking a static data member across
TU's *ought* to reference the same object. However I couldn'd find an
explicit "yes" in the Standard.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com


[ 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.