Is there a class name macro?

P

Peng Yu

Hi,

__PRETTY_FUNCTION__ is a macro that gives function name, etc. I'm
wondering if there is a macro to get the class name inside a member
function.

Thanks,
Peng
 
P

Peng Yu

Is it?


Not in standard C++.

I know __PRETTY_FUNCTION__ is not in the standard. But the standard
has something similar to it, I just do remember what it is. But my
questions was on the class name.

Thanks,
Peng
 
K

Kai-Uwe Bux

Peng said:
I know __PRETTY_FUNCTION__ is not in the standard. But the standard
has something similar to it, I just do remember what it is.

The standard has the following predefined macros [16.8]:

__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
__cplusplus__

Everything else is implementation specific.

But my questions was on the class name.

And your question has been answered: "not in standard C++".


Best

Kai-Uwe Bux
 
J

James Kanze

The standard has the following predefined macros [16.8]:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
__cplusplus__

Everything else is implementation specific.

Not entirely. A certain number of standard headers are also
guaranteed to define specific macros. In addition, C99 adds
some important macros which will doubtlessly end up in the next
standard, and in practice, should certainly be implemented by
every compiler today. (__STDC_IEC_559__ and __STDC_HOSTED__
come to mind.)

In C99, there is also a pre-defined identifier, __func__, which
contains the name of the function. C++0x will also have this,
but unlike C, given overloading, classes, namespaces and
templates, it's not clear what the string should contain.
(According to the current draft, it's implementation defined.)
And your question has been answered: "not in standard C++".

And it won't be part of the next version of the standard,
either. (At least I don't think so.)
 
J

Jorgen Grahn

It is standard C as of 1999, which is not yet a part of standard C++.

But in the part of the original post that you skipped:


...the __func__ macro, if/when it becomes part of C++, or is available
in a C++ compiler as an extension, still yields the function name, and
has nothing at all to do with the name of a class.

"Nothing at all" is a bit strongly worded -- I'd expect it to work for
member functions, and the class name to be part of it. E.g. "Foo<int>"
in "Foo<int>::bar(const Baz&)".

I have used __func__ as a C++ extension in g++, but I forget exactly
how they chose to do it. It's in the documentation though.

/Jorgen
 
J

James Kanze

Just a nit, but it's not a macro, but a pre-defined variable.
"Nothing at all" is a bit strongly worded -- I'd expect it to
work for member functions, and the class name to be part of
it. E.g. "Foo<int>" in "Foo<int>::bar(const Baz&)".

It's already present in the draft. The text is "implementation
defined", and could be simply "" in every case.
I have used __func__ as a C++ extension in g++, but I forget
exactly how they chose to do it. It's in the documentation
though.

They just output the simple function name.

The real question is what it is to be used for. What you want
to output depends on that, more than anything else. If it is
for logging messages, I'm not sure what is best. To find the
actual function, you need the fully qualified name, and even
that causes problems for anything in anonymous namespaces, or
member functions of local classes. And what about static
functions.

If the goal of putting it in a log file is to be able to find
the place in the source code later, a better solution is to use
__FILE__, __LINE__ and the version number inserted by your
version control system.
 
C

Chris Gordon-Smith

James said:
Just a nit, but it's not a macro, but a pre-defined variable.



It's already present in the draft. The text is "implementation
defined", and could be simply "" in every case.


They just output the simple function name.

The real question is what it is to be used for.

I'll probably use it in my trace utility. In most cases I put classes in
files with the name of the class, so using
__FILE__ __func__ and __LINE__ will put an entry in my trace file that
indicates (in the majority of cases) the class and the function. For the
cases where the class does not have the same name as the file, or cases
where a function is overloaded, the __LINE__ will resolve the ambiguity.

My code will be simpler, because instead of putting:-

TRACE(ClassName::FunctionName);

at the start of each function, I'll just put:-

TRACE;

Thanks to the OP for drawing attention to this.

Chris Gordon-Smith
www.simsoup.info
 
T

Thomas J. Gritzan

Peng said:
I know __PRETTY_FUNCTION__ is not in the standard. But the standard
has something similar to it, I just do remember what it is. But my
questions was on the class name.

You can get the class name in a member using this:

typeid(*this).name()

However, the exact output depends on the implementation.
 
E

Erik Wikström

Hi,

__PRETTY_FUNCTION__ is a macro that gives function name, etc. I'm
wondering if there is a macro to get the class name inside a member
function.

Most compilers have some way of getting the qualified name of a
function, usually in the form "ReturnType Class::Function(Param1,
Param2, ...)", however different compilers have different ways of doing
it. My advice is to define a macro which expands to the correct way
based on the compiler used.
 
J

James Kanze

I'll probably use it in my trace utility. In most cases I put
classes in files with the name of the class, so using __FILE__
__func__ and __LINE__ will put an entry in my trace file that
indicates (in the majority of cases) the class and the
function.

If you have the line number, and can find the source file, then
the filename and line number should indicate unambiguously which
class and which function the trace was in.

Finding the correct source file can be a bit tricky. That's why
I suggested adding some versioning information somewhere. (The
other alternative is to put the versioning information in static
C style strings in the file, and use something like "strings" to
read it from the executable, when needed.)
For the cases where the class does not have the same name as
the file, or cases where a function is overloaded, the
__LINE__ will resolve the ambiguity.
My code will be simpler, because instead of putting:-

at the start of each function, I'll just put:-

Exactly. Generally, I think that there's such a thing as being
too succinct. But in the case of tracing, the easier it is to
use, the more it will be used. And that's what you want.
 
T

tony_in_da_uk

Hi,

__PRETTY_FUNCTION__ is a macro that gives function name, etc. I'm
wondering if there is a macro to get the class name inside a member
function.

Thanks,
Peng

Your question almost answers itself. Just do a little parsing on the
__PRETTY_FUNCTION__ string to extract the class name. From quick
thought, I can't see any issue with scanning for '(' then working
backwards to "::" then taking the preceding identifier. You've got it
easy, as the types are already resolved for you - raw source code can
have templated types being instantiated with arbitrary expressions
also containing "(" etc..

Cheers,
Tony
 
T

tony_in_da_uk

Your question almost answers itself. Just do a little parsing on the
__PRETTY_FUNCTION__ string to extract the class name. From quick
thought, I can't see any issue with scanning for '(' then working
backwards to "::" then taking the preceding identifier. You've got it
easy, as the types are already resolved for you - raw source code can
have templated types being instantiated with arbitrary expressions
also containing "(" etc..

std::string less_pretty(const char pretty_func[])
{
const char* p = strrchr(pretty_func, '(');
BOOTSTRAP_ASSERT(p);
const char* end = p;
while (p[-1] != ':' && p[-1] != ' ')
--p;
BOOTSTRAP_ASSERT(p > pretty_func); // should always be space after
type...
const char* fn_name = p;
if (p[-1] == ':')
{
p -= 2;
BOOTSTRAP_ASSERT(p > pretty_func && *p == ':');
while (p > pretty_func && (isalnum(p[-1]) || p[-1] == '_'))
--p;
// simplify constructors "idn::idn()" back to idn()...
if (strncmp(p, fn_name, fn_name - p - sizeof(" ")) == 0)
p = fn_name;
}
// std::cerr << "less_pretty('" << pretty_func << "') return '"
// << std::string(p, end - p) << "'\n";
return std::string(p, end - p);
}
 
J

Jorgen Grahn

They just output the simple function name.

Yes, you're right. Strange when you think of it -- you can have lots
of operator< (), set() and so on in even a medium-sized program.
The real question is what it is to be used for. What you want
to output depends on that, more than anything else. If it is
for logging messages, I'm not sure what is best. To find the
actual function, you need the fully qualified name, and even
that causes problems for anything in anonymous namespaces, or
member functions of local classes. And what about static
functions.

Surely the purpose is log/trace messages, assertions and so on. I can
see no other reason to have it, especially since it's
implementation-defined.
If the goal of putting it in a log file is to be able to find
the place in the source code later, a better solution is to use
__FILE__, __LINE__ and the version number inserted by your
version control system.

And version number isn't needed if you have some out-of-band way of
knowing what version produced the message, and finding the source code
for that version.

I have to say that for me, __func__ *is* useful.

I have used "date time: file:line function(): ..." a lot for log/trace
messages in one application. File and line is enough to find the
source code, but the function name gives context to the message you
are printing, so that the message itself can be more brief.

I have also been hacking code which used function names in trace
messages, but didn't use __func__. It's painful -- it gets in the way
when reading the code because function names appear in the strings
(false positives when you search or grep). Also, you can bet money
that some of the strings are incorrect due to cut & paste errors.

/Jorgen
 
C

Chris Gordon-Smith

James Kanze wrote:

If you have the line number, and can find the source file, then
the filename and line number should indicate unambiguously which
class and which function the trace was in.

Finding the correct source file can be a bit tricky. That's why
I suggested adding some versioning information somewhere. (The
other alternative is to put the versioning information in static
C style strings in the file, and use something like "strings" to
read it from the executable, when needed.)

I don't get your point. Can you explain?
I always trace the latest version of my program and the trace output will
include the filename, so why is finding the source file a bit tricky?

And why is versioning information needed, and what would that information
be?
Exactly. Generally, I think that there's such a thing as being
too succinct. But in the case of tracing, the easier it is to
use, the more it will be used. And that's what you want.
Yes, code must be easy to understand. My take on it would be that succinct
code is OK so long as it does not become cryptic and impenetrable.

Chris Gordn-Smith
www.simsoup.info
 
J

James Kanze

I don't get your point. Can you explain?

As soon as you have two or more instances of the program,
fatally, sooner or later, you'll run into the problem of
different versions. And to exploit filename/line number, you
need to know the version of the file which created the trace.
I've almost always seen this in the form of static variables in
the code, and I've almost always had issues finding out which
executable generated the trace, and getting a copy of it, so
that I could know which version of the program generated the
trace. When all is said and done, it's probably a good idea to
add this information to the trace automatically. (And having
the trace macro refer to it ensures that it will be there; all
too often, I've found it missing completely, and you just have
to guess.)
I always trace the latest version of my program and the trace
output will include the filename, so why is finding the source
file a bit tricky?

If there is only one instance of the program in existance at any
one time, there's no problem. In practice, however, this isn't
the case that often.
And why is versioning information needed, and what would that
information be?
Yes, code must be easy to understand. My take on it would be
that succinct code is OK so long as it does not become cryptic
and impenetrable.

Succinctness is, in itself, a quality. Good code should be
clear and concise. Generally speaking, however, using macros to
make code more succinct, and especially using a macro to hide a
function call, costs too much clarity to be considered. Tracing
is, IMHO, a special case, however: it's not part of the program
logic, and you really have to make it as easy to use as
possible, so that it will be used. (And of course, you want to
invoke it via a macro anyway, so that you can automatically
insert __FILE__ and __LINE__.)
 
C

Chris Gordon-Smith

James said:
As soon as you have two or more instances of the program,
fatally, sooner or later, you'll run into the problem of
different versions. And to exploit filename/line number, you
need to know the version of the file which created the trace.
I've almost always seen this in the form of static variables in
the code, and I've almost always had issues finding out which
executable generated the trace, and getting a copy of it, so
that I could know which version of the program generated the
trace. When all is said and done, it's probably a good idea to
add this information to the trace automatically. (And having
the trace macro refer to it ensures that it will be there; all
too often, I've found it missing completely, and you just have
to guess.)
OK - I see the point.

In my case things are a lot simpler. I'm doing a one person spare time
project so I don't have multiple program instances / parallel realease, and
I always know which execuatble generated trace output.
If there is only one instance of the program in existance at any
one time, there's no problem. In practice, however, this isn't
the case that often.



Succinctness is, in itself, a quality. Good code should be
clear and concise. Indeed.
Generally speaking, however, using macros to
make code more succinct, and especially using a macro to hide a
function call, costs too much clarity to be considered. Tracing
is, IMHO, a special case, however: it's not part of the program
logic, and you really have to make it as easy to use as
possible, so that it will be used. (And of course, you want to
invoke it via a macro anyway, so that you can automatically
insert __FILE__ and __LINE__.)
I agree that in this case using a macro is OK (I suppose I must since I've
done it!). Macros do need to be used sparingly, and its important to keep
them as simple as possible. My TRACE macro has a single line, and by
calling the macro just once at the start of a function I get an 'Enter
Function' trace line and a second 'Leave Function' line just before the
function returns.

Another advantage of using a macro is that I can (and do) conditionally
compile it, so that I can completely remove the Trace code (although I can
also control it programmatically). Conditional compilation should also be
used sparingly, and this is the only place I use it in what has now become
a substantial sized project.

Another place I use macros is to replace curly brackets. Eg

// Global include

#define THEN {
#define ELSEIF }else if
#define ELSE }else{
#define ENDIF }
// -----------------

Then I can write

if (condition)
THEN
// Do something
ELSE
// Do something else
ENDIF

This may be controversial, but I think it makes code clearer. My code
automatically documents where the various parts of the if statement are,
rather than leaving the reader to count brackets and look at indentation.

Chris Gordon-Smith
www.simsoup.info
 
J

Jorgen Grahn

OK - I see the point.

In my case things are a lot simpler. I'm doing a one person spare time
project so I don't have multiple program instances / parallel realease, and
I always know which execuatble generated trace output.

It depends a lot on who your customers are. Where I am right now, they
are fairly close, and I can make demands. I make a point of only
giving them releases which can be traced back to one version of the
source code, and they know (or can find out) which release they are
using. Come to think of it, it's printed first in the log file.

In that scenario, file and line is enough.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top