473,399 Members | 2,858 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,399 software developers and data experts.

solution: an in-language way of mapping class names --> strings

Good afternoon, C++ers,

This weekend i came across a fairly project-neutral trick which can be used
to map C++ class names to their human-readable equivalents (a-la QObject's
className() method), without having to add methods to a client interface
and without relying on (e.g.) typeid(T).name().

i understand that this may not be strictly a language-related post, but i
think the solution is "template-enough" to be considered topical here.

Sample usage:
#include "class_name.h"
....
CLASS_NAME(MyClass);
....
cout << class_name<MyClass>() << endl;
or
cout << class_name<MyClass>::name() << endl;

the code:

#ifndef CLASS_NAME_H_INCLUDED
#define CLASS_NAME_H_INCLUDED 1
#include <cassert>

namespace { // anonymous ns, important for linking reasons.

/**
A utility class to provide human-usable class names, available at
runtime.

It MUST be specialized to work.

Call the CLASS_NAME(Type) or
CLASS_NAME_ALIAS(Type,AliasForType) macros from somewhere
in the global namespace (in a header, not an impl file) to
register a class_name<Type> specialization for Type. It may
only be called one time per Type per compilation unit, or
you will get specialization collisions at compile time.

Ideally, CLASS_NAME() is called from a class' header file.

Caveats:

- template types with commas in the names will break the
macro and...

- typedef'd names will get their typedef'd name, not their
real name. Maybe a feature, maybe not.
*/
template <class T> struct class_name
{
// static const char * classname = "...";
// ^^^^ we can't initalized a non-integral type this way,
thus the bloat show below...

class_name(){}
~class_name(){}
static const char * name()
{
assert( 0 /* this class_name<> is unspecialized!
*/ );
return "error::class_name<unspecialized>";
}
operator const char * () const
{
return name();
}
};

} // namespace

#define CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,Type)
#define CLASS_NAME_ALIAS(Type,Alias) \
namespace {\
template <> struct class_name<Type> {\
class_name(){}; ~class_name(){}; \
static const char * name() {return # Alias; }\
operator const char * () const { return name(); }\
};}
#endif // CLASS_NAME_H_INCLUDED

i now use this as the basis for a classloader.

Enjoy...

--
----- stephan beal
Registered Linux User #71917 http://counter.li.org
I speak for myself, not my employer. Contents may
be hot. Slippery when wet. Reading disclaimers makes
you go blind. Writing them is worse. You have been Warned.

Jul 19 '05 #1
5 2942
On Wed, 15 Oct 2003 12:18:47 +0200, stephan beal
<st*****@wanderinghorse.net> wrote:
Good afternoon, C++ers,

This weekend i came across a fairly project-neutral trick which can be used
to map C++ class names to their human-readable equivalents (a-la QObject's
className() method), without having to add methods to a client interface
and without relying on (e.g.) typeid(T).name().

i understand that this may not be strictly a language-related post, but i
think the solution is "template-enough" to be considered topical here.
Standard C++ idioms are certainly on topic.
#ifndef CLASS_NAME_H_INCLUDED
#define CLASS_NAME_H_INCLUDED 1
#include <cassert>

namespace { // anonymous ns, important for linking reasons.
Why? All your methods are inline so you're better off putting the
class in the global namespace, IMHO, so that instantiations might be
shared. In practice, everything will be inlined so it probably doesn't
make much difference either way.

/**
A utility class to provide human-usable class names, available at
runtime.

It MUST be specialized to work.

Call the CLASS_NAME(Type) or
CLASS_NAME_ALIAS(Type,AliasForType) macros from somewhere
in the global namespace (in a header, not an impl file) to
register a class_name<Type> specialization for Type. It may
only be called one time per Type per compilation unit, or
you will get specialization collisions at compile time.

Ideally, CLASS_NAME() is called from a class' header file.

Caveats:

- template types with commas in the names will break the
macro and...

- typedef'd names will get their typedef'd name, not their
real name. Maybe a feature, maybe not.
*/
template <class T> struct class_name
{
// static const char * classname = "...";
// ^^^^ we can't initalized a non-integral type this way,
thus the bloat show below...

class_name(){}
~class_name(){}
static const char * name()
{
assert( 0 /* this class_name<> is unspecialized!
*/ );
return "error::class_name<unspecialized>";
}
operator const char * () const
{
return name();
}
};
How about:

template <class T> struct class_name; //no definition

That way you'll get compile time errors when trying to use it with
unregistered classes.

} // namespace

#define CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,Type)
#define CLASS_NAME_ALIAS(Type,Alias) \
namespace {\
template <> struct class_name<Type> {\
class_name(){}; ~class_name(){}; \
Why the empty constructor and destructor? The compiler will generate
them for you.
static const char * name() {return # Alias; }\
operator const char * () const { return name(); }\
};}
#endif // CLASS_NAME_H_INCLUDED

i now use this as the basis for a classloader.


It's a good idea.

Tom
Jul 19 '05 #2
tom_usenet wrote:
On Wed, 15 Oct 2003 12:18:47 +0200, stephan beal
<st*****@wanderinghorse.net> wrote:
namespace { // anonymous ns, important for linking reasons.
Why? All your methods are inline so you're better off putting the
class in the global namespace, IMHO, so that instantiations might be
shared. In practice, everything will be inlined so it probably doesn't
make much difference either way.


This is a valid point. First, let me agree that it "probably" doesn't make a
difference. i ended up using an anon namespace because:

a) i was using no global-space code in the tree which this evolved from.
b) because i had lots of dual-definition collisions when puting class_name
into those namespaces (i don't know why,though).

That said, the ODR violations were very possibly caused by me doing
something stupid as far as include files went. Since the anon ns seems to
work okay i stick with that. (i'm new to template specialization and want
to remove as many variables (no pun intended) as possible while i learn the
ropes.)

Part of the complication is that many of my CLASS_NAME() usages are in
classes which are compiled into static libraries and/or DLLs (or both). To
avoid template-instantiation-related problems i keep the CLASS_NAME() calls
in the class*headers, NOT in their impl files (which would be okay if all
the participating classes are in the same lib/app).

Again, though, i'll admit that i'm fairly new to this level of linking
complication, and i may be using a naive approach. "It seems to work," but
there may be a better way to handle that. i'll give it a try using the
global NS, as you suggest. i believe that my anon-ns implementation has an
evil side-effect in my classloader, anyway, causing multiple-registations
for classes where CLASS_NAME() is called from several impl files (that's
another matter entirely, however, and one which i'll cover in a separate
post).
It's a good idea.


Thanks :)
i appreciate the feedback!

--
----- stephan beal
Registered Linux User #71917 http://counter.li.org
I speak for myself, not my employer. Contents may
be hot. Slippery when wet. Reading disclaimers makes
you go blind. Writing them is worse. You have been Warned.

Jul 19 '05 #3
tom_usenet wrote:
}

Sorry, i completely missed these notes in my first response:
How about:

template <class T> struct class_name; //no definition

That way you'll get compile time errors when trying to use it with
unregistered classes.
That's a great idea, thanks :).
Why the empty constructor and destructor? The compiler will generate
them for you.


Habit :/
--
----- stephan beal
Registered Linux User #71917 http://counter.li.org
I speak for myself, not my employer. Contents may
be hot. Slippery when wet. Reading disclaimers makes
you go blind. Writing them is worse. You have been Warned.

Jul 19 '05 #4
tom_usenet wrote:
On Wed, 15 Oct 2003 12:18:47 +0200, stephan beal
<st*****@wanderinghorse.net> wrote:
namespace { // anonymous ns, important for linking reasons.


Why? All your methods are inline so you're better off putting the
class in the global namespace, IMHO, so that instantiations might be
shared. In practice, everything will be inlined so it probably doesn't
make much difference either way.


i experimented with this a bit last night, and the problem is rather
complex, but boils down to requiring an anonymous namespace.

It's like this:

i've got classes which are used in these different contexts:

a) in a static lib
b) in a DLL with a group of other classes
c) alone in a DLL
d) statically linked directly by client apps

The anon ns is the only way i can reliably link all of these cases without
getting multiple definition collisions at link time. Not only that, but the
CLASS_NAME stuff must be called in the class HEADERs, not the impl files,
or else some of the above contexts will work and some will not. e.g., let's
assume we do this in Foo.cpp:

CLASS_NAME(Foo);

the class_name<Foo> specialization gets compiled into Foo.o. Now we link
Foo.o into mylib.a - the specialization doesn't survive the trip, requiring
the client to link against Foo.o. Calling the macro from the header gets
around this in all known cases at the slight cost of a couple extra
instantiations.

--
----- stephan beal
Registered Linux User #71917 http://counter.li.org
I speak for myself, not my employer. Contents may
be hot. Slippery when wet. Reading disclaimers makes
you go blind. Writing them is worse. You have been Warned.

Jul 19 '05 #5
On Thu, 16 Oct 2003 12:15:45 +0200, stephan beal
<st*****@wanderinghorse.net> wrote:
tom_usenet wrote:
On Wed, 15 Oct 2003 12:18:47 +0200, stephan beal
<st*****@wanderinghorse.net> wrote:
namespace { // anonymous ns, important for linking reasons.
Why? All your methods are inline so you're better off putting the
class in the global namespace, IMHO, so that instantiations might be
shared. In practice, everything will be inlined so it probably doesn't
make much difference either way.


i experimented with this a bit last night, and the problem is rather
complex, but boils down to requiring an anonymous namespace.

It's like this:

i've got classes which are used in these different contexts:

a) in a static lib
b) in a DLL with a group of other classes
c) alone in a DLL
d) statically linked directly by client apps


Ahh, I can see that might cause problems.
The anon ns is the only way i can reliably link all of these cases without
getting multiple definition collisions at link time. Not only that, but the
CLASS_NAME stuff must be called in the class HEADERs


Yes, of course - specializations have to have been declared in order
to legally use them, although some compilers let you get away with
this.

Tom
Jul 19 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Ares Lagae | last post by:
When adopting the coding style of the standard C++ library, you often run into naming problems because class names are lower case, and member functions do not have get/set prefixes. For example:...
4
by: Erkan KURTULUŞ | last post by:
Hi, How can i found all class names in a namespace?. My aim is reach all attributes of classes. Best Regards Erkan
0
by: Ivan A. Kosarev | last post by:
Hello, There are three similar programs below. All of these use typedef names, qualified identifiers, class names and name lookup mechanism in various contexts. I found that most respect C++...
1
by: steeren | last post by:
Hi, I'm new to this forum, so hello there. I have been working on getting some tool generated markup, to use a class name convention that can then be mapped to the platform its running on - with...
0
by: RYoung | last post by:
Hi all, Hope no one minds this long message, but I'm puzzled: --------------- The following is a shortened version of schema located at...
23
by: mike3 | last post by:
Hi. (posted to both newsgroups since I was not sure of which would be appropriate for this question or how specific to the given language it is. If one of them is inappropriate, just don't send...
5
by: alan | last post by:
Hello world, I'm wondering if it's possible to implement some sort of class/object that can perform mapping from class types to strings? I will know the class type at compile time, like so:...
4
by: Steven Simpson | last post by:
Stefan Ram wrote (in "More than one language in a page"): Is this a new trend of user-agent writers (Microformats, and now Google) staking claims on the @class namespace? I'm surely not the only...
1
by: spyderfusion02 | last post by:
Hi there, I am trying to get the class names dynamically for the script below. I am using the Pagination plugin. I have different class names that are created through PHP so need to get them using...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.