Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

g++-question

157 views
Skip to first unread message

Bonita Montero

unread,
Jan 29, 2020, 9:47:52 AM1/29/20
to
With this:

#include <iostream>
#include <typeinfo>

using namespace std;

int main()
{
int A, C;
float B;
long long D;
int (*E)[];
cout << typeid(A + B).name() << endl;
cout << typeid(A + C).name() << endl;
cout << typeid(A + D).name() << endl;
cout << typeid(E).name() << endl;
}

... I get ...

float
int
__int64
int (* __ptr64)[0]

... with MSVC.

With g++ I get ...

f
i
x
PA_i

Does anyone know how to make gcc more expressive like MSVC?

red floyd

unread,
Jan 29, 2020, 9:58:18 AM1/29/20
to
You probably can't. The value of std::type_info.name() is
implementation defined.


Bonita Montero

unread,
Jan 29, 2020, 9:59:31 AM1/29/20
to
>> Does anyone know how to make gcc more expressive like MSVC?

> You probably can't.  The value of std::type_info.name() is
> implementation defined.

I know, but probably there's a compiler-switch.

Bonita Montero

unread,
Jan 29, 2020, 10:44:24 AM1/29/20
to
That's a workaround:

#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <string>

using namespace std;

int main()
{
unordered_map<type_index, string> typeMappings;
typeMappings[type_index( typeid(char) )] = "char";
typeMappings[type_index( typeid(unsigned char) )] = "unsigned
char";
typeMappings[type_index( typeid(signed char) )] = "signed char";
typeMappings[type_index( typeid(short) )] = "short";
typeMappings[type_index( typeid(unsigned short) )] = "unsigned
short";
typeMappings[type_index( typeid(int) )] = "int";
typeMappings[type_index( typeid(unsigned int) )] = "unsigned
int";
typeMappings[type_index( typeid(long) )] = "long";
typeMappings[type_index( typeid(unsigned long) )] = "unsigned
long";
typeMappings[type_index( typeid(long long) )] = "long long";
typeMappings[type_index( typeid(unsigned long long) )] = "unsigned
long long";
typeMappings[type_index( typeid(float) )] = "float";
typeMappings[type_index( typeid(double) )] = "double";
typeMappings[type_index( typeid(long double) )] = "long double";

int a, c;
float b;
long long d;
cout << typeMappings[type_index( typeid(a + b) )] << endl;
cout << typeMappings[type_index( typeid(a + c) )] << endl;
cout << typeMappings[type_index( typeid(a + d) )] << endl;
}

Melzzzzz

unread,
Jan 29, 2020, 11:06:00 AM1/29/20
to
I can't remember but there is function to demangle typeid name...

--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Melzzzzz

unread,
Jan 29, 2020, 11:08:11 AM1/29/20
to
On 2020-01-29, Melzzzzz <Melz...@zzzzz.com> wrote:
> On 2020-01-29, Bonita Montero <Bonita....@gmail.com> wrote:
>>>> Does anyone know how to make gcc more expressive like MSVC?
>>
>>> You probably can't.  The value of std::type_info.name() is
>>> implementation defined.
>>
>> I know, but probably there's a compiler-switch.
> I can't remember but there is function to demangle typeid name...
>

Here it is:
https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html

bol...@nowhere.org

unread,
Jan 29, 2020, 12:16:58 PM1/29/20
to
On Wed, 29 Jan 2020 15:47:43 +0100
Bonita Montero <Bonita....@gmail.com> wrote:
>With this:
>
>#include <iostream>
>#include <typeinfo>
>
>using namespace std;
>
>int main()
>{
> int A, C;
> float B;
> long long D;
> int (*E)[];
> cout << typeid(A + B).name() << endl;
> cout << typeid(A + C).name() << endl;
> cout << typeid(A + D).name() << endl;
> cout << typeid(E).name() << endl;
>}
>
>.... I get ...
>
>float
>int
>__int64
>int (* __ptr64)[0]
>
>.... with MSVC.
>
>With g++ I get ...
>
>f
>i
>x
>PA_i
>
>Does anyone know how to make gcc more expressive like MSVC?

Its compiler dependant so no.

FWIW Clang gives the same output as gcc.

bol...@nowhere.org

unread,
Jan 29, 2020, 12:17:59 PM1/29/20
to
On Wed, 29 Jan 2020 16:44:15 +0100
Bonita Montero <Bonita....@gmail.com> wrote:
>That's a workaround:

Not sure you'd define creating a map with the long format as a "workaround" :)


Alf P. Steinbach

unread,
Jan 29, 2020, 9:12:38 PM1/29/20
to
If you're only interested in understanding the short output of a little
g++ test program, then you can use the `c++filt -t` command.

A clean type name utility needs to clean up not only the g++ result but
also the Visual C++ result, and maybe also other schemes used by other
compilers.

Code for the two mentioned compilers can go like the following, which is
available at <url:
https://github.com/alf-p-steinbach/cppx-core-language/blob/master/source/cppx-core-language/type-checking/type_name_from.hpp>:


#pragma once // Source encoding: UTF-8 with BOM (π is a lowercase
Greek "pi").
#include <cppx-core-language/assert-cpp/is-c++17-or-later.hpp>

#include <cppx-core-language/syntax/collection-util/Sequence_.hpp> //
cppx::Sequence_
#include <cppx-core-language/syntax/types/type-builders.hpp> //
cppx::Type_
#include <cppx-core-language/syntax/declarations.hpp> //
CPPX_USE_...
#include <cppx-core-language/text/ascii-character-util.hpp> //
cppx::ascii::*
#include <cppx-core-language/tmp/Type_carrier_.hpp> //
cppx::Type_carrier_
#include <cppx-core-language/tmp/type-modifiers.hpp> //
cppx::As_referent_

#include <functional> // std::invoke
#include <stdlib.h> // free
#include <string> // std::string
#include <typeinfo> // std::type_info
#include <utility> // std::forward

#ifdef __GNUC__
# include <cxxabi.h>
#endif

namespace cppx
{
CPPX_USE_STD( forward, invoke, string, type_info );

inline auto type_name_from( const type_info& info )
-> string;

#ifdef __GNUC__
inline auto type_name_from( const type_info& info )
-> string
{
struct Malloced_string
{
Type_<const char*> p_chars;
~Malloced_string() { free( const_cast<char*>( p_chars ) ); }
};

const Type_<const char*> mangled_name = info.name();
int status = 0;
const Malloced_string demangled = { ::abi::__cxa_demangle(
info.name(),
nullptr, // Output buffer
nullptr, // length
&status
) };
return (status == 0? demangled.p_chars : mangled_name);
}
#else
namespace impl {
inline auto is_ascii_separator( const char ch )
-> bool
{
if( not ascii::contains( ch ) ) { return false; }
return not ascii::is_identifier_character( ch );
};

inline auto is_identifier_character( const char ch )
-> bool
{ return not is_ascii_separator( ch ); }
} // namespace impl

inline auto type_name_from( const type_info& info )
-> string
{
const string elaborated = string( info.name() ) + '\0';
// MSVC example: "".

string result;
string part;
bool is_in_name = false;

// Assemble the parts except ditch MSVC's "struct", "class" and
"enum" keywords.
for( char ch: elaborated ) {
if( impl::is_identifier_character( ch ) ) {
is_in_name = true;
part += ch;
} else {
if( is_in_name ) {
// Finish this part.
if( part == "struct" or part == "class" or part ==
"enum" ) {
// Ignore these keywords.
if( ascii::is_whitespace( ch ) ) {
ch = '\0'; // Don't add this
whitespace to the result.
}
} else {
result += part;
}

part = "";
is_in_name = false;
}

if( ch != '\0' ) {
result += ch;
}
}
}
return result;
}
#endif

} // namespace cppx


Disclaimer: as I recall this isn't unit-tested. Just "OK, it works" for
some given context.


- Alf

Sam

unread,
Jan 31, 2020, 7:06:23 AM1/31/20
to
No, there isn't. There is no valid reason to have such a compiler option in
the first place.

Bonita Montero

unread,
Jan 31, 2020, 7:38:43 AM1/31/20
to
There is a reason: depending on the type of usage of typeid(x).name()
you want to get the internal type-representation for efficient hand-
ling or the readable representation for debugging-purposes.

David Brown

unread,
Jan 31, 2020, 8:03:34 AM1/31/20
to
No, there is no reason to have such a switch - name() is not intended to
give human-readable results, merely an identifier. So compilers handle
it in different ways.

Anyway, a few seconds googling gives this:

<https://en.cppreference.com/w/cpp/types/type_info/name>

<https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html>

Hopefully that should give you what you need.

Bonita Montero

unread,
Jan 31, 2020, 8:15:39 AM1/31/20
to
> No, there is no reason to have such a switch - name() is not intended to
> give human-readable results, ...

I told you the reason: it would be good for debugging-purposes.
It may be not your taste how this might be implemented, but there
are good reasons to make it the way I described.

Paavo Helde

unread,
Jan 31, 2020, 9:01:36 AM1/31/20
to
The typeid names are implementation specific anyway, so nothing has
stopped gcc folks to generate more verbose names. The fact that they
have not done so indicates that they have thought about it and selected
the current solution as "the best". Why should they add another
inconsistent behavior which would not be "the best"? And maybe you want
to have both representations in a TU, a compiler switch would not help
at all with this.

Moreover, if there was such a compiler switch, it might cause glitches
or inconsistent behavior when linking together libraries compiled with
different options. Any potential benefit would not outweigh the loss of
consistency, especially considering that it is trivial to add an
abi::__cxa_demangle() call when needed.


Bart

unread,
Jan 31, 2020, 9:12:06 AM1/31/20
to
Not so trivial since none of the following seems to work, 'abi' being
undefined in every case:

#include <abi>
#include <abi.h>
abi::__cxa_demangle(typeid(x).name())

Bonita Montero

unread,
Jan 31, 2020, 9:16:00 AM1/31/20
to
> The typeid names are implementation specific anyway, ...

But they could be verbose for debugging-purposes.

> The typeid names are implementation specific anyway, so nothing has
> stopped gcc folks to generate more verbose names. The fact that they
> have not done so indicates that they have thought about it and selected
> the current solution as "the best". Why should they add another
> inconsistent behavior which would not be "the best"?

Getting the typename isn't good for nothing more than debugging
-purposes. So there should be at least an option to have it verbose.
You can completely disable typeinfo; I think the first reason for that
is to make it harder to reverse-engineer code. If there's such an option
there could be also the option I have in mind.

> Moreover, if there was such a compiler switch, it might cause glitches
> or inconsistent behavior when linking together libraries compiled with
> different options.

There are also "glitches" if you disable typeid by compilerswitch
also; and no one cares for that. That's not a real issue.

Paavo Helde

unread,
Jan 31, 2020, 9:27:30 AM1/31/20
to
Just include the correct header:

#include <iostream>
#include <cxxabi.h>

int main() {
int x = 42;
int status;
std::cout << abi::__cxa_demangle(typeid(x).name(), 0, 0, &status) << "\n";
}




James Kuyper

unread,
Jan 31, 2020, 9:30:23 AM1/31/20
to
On 1/31/20 8:03 AM, David Brown wrote:
> On 31/01/2020 13:38, Bonita Montero wrote:
>>>>>> Does anyone know how to make gcc more expressive like MSVC?
>>
>>>>> You probably can't.  The value of std::type_info.name() is
>>>>> implementation defined.
>>
>>>> I know, but probably there's a compiler-switch.
>>
>>> No, there isn't. There is no valid reason to have such a compiler
>>> option in the first place.
>>
>> There is a reason: depending on the type of usage of typeid(x).name()
>> you want to get the internal type-representation for efficient hand-
>> ling or the readable representation for debugging-purposes.
>
> No, there is no reason to have such a switch - name() is not intended to
> give human-readable results, merely an identifier. So compilers handle
> it in different ways.

I've reached the same conclusion, based upon precisely the opposite
premises. There's nothing that can usefully be done with the string
returned by name() EXCEPT print it out for humans to read. It's only
purpose is to be human-readable.

However, the issues of precisely what the string should say were
sufficiently complicated that the committee elected to leave them for
each implementation to decide. If an implementation doesn't produce
results that are as easy to understand as you'd like, that's because the
implementors decided that more useful results were not sufficiently
valuable to justify the (considerable) difficulty of producing them. A
compiler switch to enable more useful results therefore makes no sense.
In order to support that switch, they'd need to put in that extra
effort, which is what they were trying to avoid. If and when they do end
up deciding to put in that effort, why provide an option which, if not
selected, allows for the less useful results?

Öö Tiib

unread,
Jan 31, 2020, 9:41:27 AM1/31/20
to
Most fruitful is to add text serialization support to data. Serialization
can be useful for lot of other things than debugging. Work needed
depends on serialization library used, on better cases it can be
conditionally compiled out in release builds, and result will look
something like:

std::cout /* or my::logger */ << json::make_from(x) << '\n';


Bonita Montero

unread,
Jan 31, 2020, 10:09:52 AM1/31/20
to
> Just include the correct header:
> #include <iostream>
> #include <cxxabi.h>
> int main() {
>     int x = 42;
>     int status;
>     std::cout << abi::__cxa_demangle(typeid(x).name(), 0, 0, &status)
> << "\n";
> }

That's rather a workaround for me.

Bonita Montero

unread,
Jan 31, 2020, 10:12:29 AM1/31/20
to
> Most fruitful is to add text serialization support to data.

That doesn't make sense since the extraced name from typeid(x).name()
wouldn't help you when deserializing. Using type_index( typeid(x) )
to map through a hashtable to a deserialization-function would be
a possible solution.

David Brown

unread,
Jan 31, 2020, 10:32:11 AM1/31/20
to
On 31/01/2020 15:30, James Kuyper wrote:
> On 1/31/20 8:03 AM, David Brown wrote:
>> On 31/01/2020 13:38, Bonita Montero wrote:
>>>>>>> Does anyone know how to make gcc more expressive like MSVC?
>>>
>>>>>> You probably can't.  The value of std::type_info.name() is
>>>>>> implementation defined.
>>>
>>>>> I know, but probably there's a compiler-switch.
>>>
>>>> No, there isn't. There is no valid reason to have such a compiler
>>>> option in the first place.
>>>
>>> There is a reason: depending on the type of usage of typeid(x).name()
>>> you want to get the internal type-representation for efficient hand-
>>> ling or the readable representation for debugging-purposes.
>>
>> No, there is no reason to have such a switch - name() is not intended to
>> give human-readable results, merely an identifier. So compilers handle
>> it in different ways.
>
> I've reached the same conclusion, based upon precisely the opposite
> premises. There's nothing that can usefully be done with the string
> returned by name() EXCEPT print it out for humans to read. It's only
> purpose is to be human-readable.

If I understand it correctly (from reading the links I posted), gcc and
clang specifically choose to give the names using the mangling format
specified by the Itanium C++ ABI. (Why the Itanium C++ ABI? I don't
know, but I suppose its as good as any.) So they are giving a
well-defined format that can be used by other software that follows the
same standard. That includes the symbol names generated by the tools.
Assuming I understand this all correctly, it means you can get the
mangled symbol name for "foo(T)" by combing "foo" and
"std::type_info.name(T)". This could have many more uses than just
human-readable output.

And you can get a more readable version from the abi::__cxa_demangle
function.

So gcc and clang gives a more useful and flexible solution here, though
it requires a little more effort to use it in human debugging.

>
> However, the issues of precisely what the string should say were
> sufficiently complicated that the committee elected to leave them for
> each implementation to decide. If an implementation doesn't produce
> results that are as easy to understand as you'd like, that's because the
> implementors decided that more useful results were not sufficiently
> valuable to justify the (considerable) difficulty of producing them. A
> compiler switch to enable more useful results therefore makes no sense.
> In order to support that switch, they'd need to put in that extra
> effort, which is what they were trying to avoid. If and when they do end
> up deciding to put in that effort, why provide an option which, if not
> selected, allows for the less useful results?
>

I can't imagine it would have been terribly difficult for gcc to pass
the type info strings through abi::__cxa-demangle to get a more human
readable version of name(). The abi:: stuff will already be used in the
compiler. But any switch here changing the output of name() would break
other uses of it, and so be a terrible idea.

Manfred

unread,
Jan 31, 2020, 11:15:41 AM1/31/20
to
I believe the keyword here is well-defined (possibly together with
efficiency). Using the mangled name results in a 1:1 relationship
between name() and the C++ type, whereas a human readable name would end
up with things like "int unsigned" "unsigned int" and "unsigned" all
denoting the same type. Assuming the priority is to provide a name
somehow usable by the software, this kind of 1:1 equivalence is valuable.
Moreover, some mangled names need to end up in the executable for
dynamic linking anyway, so having name() return the same encoding can
save some duplication.


That includes the symbol names generated by the tools.
> Assuming I understand this all correctly, it means you can get the
> mangled symbol name for "foo(T)" by combing "foo" and
> "std::type_info.name(T)". This could have many more uses than just
> human-readable output.
>
> And you can get a more readable version from the abi::__cxa_demangle
> function.

Which is perfectly suitable for debugging purposes.

Öö Tiib

unread,
Feb 1, 2020, 6:20:01 AM2/1/20
to
Yes typeid(x).name() is better not to use or to use some library
that converts it into more useful form.
The type indexes may change when we change code or use different
compilers so most of reflection information needed for
deserialization has to be entered manually, generated with macros
and/or generated with code generator tools.

Bonita Montero

unread,
Feb 1, 2020, 10:56:53 AM2/1/20
to
> The type indexes may change when we change code or use different
> compilers ...

That doesn't matter as the indexes aren't persisted.
They're only used to map the serialization-code to a datatype.

> ..., generated with macros and/or generated with code generator tools.

Macros are only needed for conditional compilation in C++.
In other cases they're bad code.

Öö Tiib

unread,
Feb 1, 2020, 1:44:54 PM2/1/20
to
What are you talking about? You made a thread that the typeid(x).name()
does not work. Yes it does not work. Therefore you have to stringize
type name with macro, code generating tool or to type it in with your
hands. What else? I just suggest to use
serialization / deserialization tools and libraries that already
inevitably contain those macros. If it is "bad" for you, then how
can I care? Too bad, don't use. :D

Bonita Montero

unread,
Feb 2, 2020, 5:18:51 AM2/2/20
to
> What are you talking about? You made a thread that the typeid(x).name()
> does not work. Yes it does not work. Therefore you have to stringize
> type name with macro, ...

I've shown how to do that without macros much cleaner.
Macros are mostly bad code in C++.

> I just suggest to use serialization / deserialization tools and
> libraries that already inevitably contain those macros. ...

No, they generate datatype-specific code.

Öö Tiib

unread,
Feb 2, 2020, 7:55:59 AM2/2/20
to
On Sunday, 2 February 2020 12:18:51 UTC+2, Bonita Montero wrote:
> > What are you talking about? You made a thread that the typeid(x).name()
> > does not work. Yes it does not work. Therefore you have to stringize
> > type name with macro, ...
>
> I've shown how to do that without macros much cleaner.

You mean what? To write it out manually for all types used in project:

typeMappings[std::type_index(typeid(typing::Festival))]
= "typing::Festival";
typeMappings[std::type_index(typeid(typing::Festival*))]
= "typing::Festival*";
typeMappings[std::type_index(typeid(typing::Festival const*))]
= "typing::Festival const*";
typeMappings[std::type_index(typeid(std::unique_ptr<typing::Festival>))]
= "std::unique_ptr<typing::Festival>";
typeMappings[std::type_index(typeid(std::vector<typing::Festival>))]
= "std::vector<typing::Festival>)";
// etc.

No thanks. It will be tedious maintenance nightmare in any project worth
writing.

> Macros are mostly bad code in C++.

Yes. Unless where other options are worse. Macros can be used to indicate
source code file, function name and line #, avoid copy-paste typos
and can be compiled to generate no code in release builds, so are
quite unavoidable in user-defined debugging facilities of C++.

> > I just suggest to use serialization / deserialization tools and
> > libraries that already inevitably contain those macros. ...
>
> No, they generate datatype-specific code.

That you suggest to write manually.

Sam

unread,
Feb 2, 2020, 8:24:39 AM2/2/20
to
Bonita Montero writes:

> Getting the typename isn't good for nothing more than debugging
> -purposes. So there should be at least an option to have it verbose.
> You can completely disable typeinfo; I think the first reason for that
> is to make it harder to reverse-engineer code. If there's such an option
> there could be also the option I have in mind.

dynamic_cast<> uses the typeinfo data. Not the entire metadata gets exposed by
typeinfo, in typical implementations, but the underlying data must include
the object's type that's encoded in some fashion. Otherwise there's no
dynamic_cast<>. So, you cannot "completely disable" typeinfo. The end result
will not be C++.

It looks to me like gcc/clang chose their compact typename encoding to serve
a double-duty: to make dynamic_cast<> find what it's looking for, and for
name(). It would be somewhat inefficient for dynamic_cast<> to use verbose
human-readable typenames, so implementations that return them must be
duplicating a little bit of data and storing both an compact typename
encoding and a human readable string in the underlying typeid (even if not
exposed via a public API); or construct the name() from scratch, and since
the string returned by name() does not have a specified lifetime, it must be
allocated in dynamic scope, for the remaining lifetime of the program.
Having name() return an encoded type string solves that problem.

Bonita Montero

unread,
Feb 2, 2020, 8:46:31 AM2/2/20
to
>> I've shown how to do that without macros much cleaner.
> You mean what? To write it out manually for all types used in project:
>
> typeMappings[std::type_index(typeid(typing::Festival))]
> = "typing::Festival";
> typeMappings[std::type_index(typeid(typing::Festival*))]
> = "typing::Festival*";
> typeMappings[std::type_index(typeid(typing::Festival const*))]
> = "typing::Festival const*";
> typeMappings[std::type_index(typeid(std::unique_ptr<typing::Festival>))]
> = "std::unique_ptr<typing::Festival>";
> typeMappings[std::type_index(typeid(std::vector<typing::Festival>))]
> = "std::vector<typing::Festival>)";
> // etc.
> No thanks. It will be tedious maintenance nightmare in any project worth
> writing.

Something like this might be generated by a persistence-generator
like protocol buffers - without the necessity of macros.

> That you suggest to write manually.

No, not at the point where you told about serialization-libs.

Öö Tiib

unread,
Feb 2, 2020, 9:03:19 AM2/2/20
to
On Sunday, 2 February 2020 15:46:31 UTC+2, Bonita Montero wrote:
> >> I've shown how to do that without macros much cleaner.
> > You mean what? To write it out manually for all types used in project:
> >
> > typeMappings[std::type_index(typeid(typing::Festival))]
> > = "typing::Festival";
> > typeMappings[std::type_index(typeid(typing::Festival*))]
> > = "typing::Festival*";
> > typeMappings[std::type_index(typeid(typing::Festival const*))]
> > = "typing::Festival const*";
> > typeMappings[std::type_index(typeid(std::unique_ptr<typing::Festival>))]
> > = "std::unique_ptr<typing::Festival>";
> > typeMappings[std::type_index(typeid(std::vector<typing::Festival>))]
> > = "std::vector<typing::Festival>)";
> > // etc.
> > No thanks. It will be tedious maintenance nightmare in any project worth
> > writing.
>
> Something like this might be generated by a persistence-generator
> like protocol buffers - without the necessity of macros.

So code generation tools of serialization libs that I suggested.

> > That you suggest to write manually.
>
> No, not at the point where you told about serialization-libs.

Why you lie like always, liar? I each time diligently mentioned
code generation tools as alternative to macros. You had your
"without macros much cleaner" nonsense. Now you argue against my
own suggestion with my own suggestion.

Robert Wessel

unread,
Feb 2, 2020, 9:05:52 AM2/2/20
to
While storing the mangled type name makes sense (although an even more
compact representation might be even better), there's no reason name()
couldn't demangle it before returning.

Bonita Montero

unread,
Feb 2, 2020, 10:29:44 AM2/2/20
to
>> No, not at the point where you told about serialization-libs.

> Why you lie like always, liar? I each time diligently mentioned
> code generation tools as alternative to macros. You had your
> "without macros much cleaner" nonsense. Now you argue against my
> own suggestion with my own suggestion.

No, you told that these code-generation-tools might use macros also.
I said that this is unclean code and not necessary.

Ian Collins

unread,
Feb 2, 2020, 1:27:04 PM2/2/20
to
On 03/02/2020 03:03, Öö Tiib wrote:


> Why you lie like always, liar?

You've been trolled.

--
Ian.

Sam

unread,
Feb 2, 2020, 6:28:32 PM2/2/20
to
The second-to-last sentence of my paragraph, quoted above, explains the
small technical complication this approach poses.

Juha Nieminen

unread,
Feb 3, 2020, 5:25:12 AM2/3/20
to
Bonita Montero <Bonita....@gmail.com> wrote:
> Macros are only needed for conditional compilation in C++.
> In other cases they're bad code.

Not always. One example where a preprocessor macro is useful is when
you want a code line number inserted into a message, eg. when doing
some debugging or printing out error messages in some testing code.

For example, wherever I write a testbed program for something,
I often do it so that I can write tests like:

if(someConditionFails)
return DPRINT("Test X failed with value ", something, ".");

In a testbed program with literally hundreds of complicated tests, it's
quite useful if that message prints the line where the DPRINT() call is
being made, as it makes it so much easier to find out which one of the
myriads of tests failed specifically. In other words, it kind of works
like an assertion failure, but with a message that can contain anything
you want, including variable value.

In other words, the above could for example print something like:

filename.cc:123: Test X failed with value 98765.

The easiest way to make it work like that is by implementing a macro
like:

#define DPRINT(...) dprint(__FILE__, __LINE__, __VA_ARGS__)

and then implement dprint() as a variadic template function.

You could avoid the macro by calling that dprint() function directly and
manually writing __FILE__ and __LINE__ every single time, but why? Making it
like this makes it easier and handier to use, and allows more easily changing
it to do something else instead. I can't think of many drawbacks.

Daniel

unread,
Feb 3, 2020, 10:34:36 AM2/3/20
to
On Monday, February 3, 2020 at 5:25:12 AM UTC-5, Juha Nieminen wrote:
> Bonita Montero <Bonita....@gmail.com> wrote:
> > Macros are only needed for conditional compilation in C++.
> > In other cases they're bad code.
>
> Not always. One example where a preprocessor macro is useful is when
> you want a code line number inserted into a message, eg. when doing
> some debugging or printing out error messages in some testing code.
>
Some boost libraries (e.g. Phoenix, Serialization) provide convenience macros for generating repetitive boilerplate code, do you think the "one of the most highly regarded and expertly designed C++ library projects in the world" got it right? or wrong? C++ serialization libraries generally make use of traits which can be a bit formidable to produce by hand, do you think providing macros to generate these is sensible? or stupid?

Best regards,
Daniel

Alf P. Steinbach

unread,
Feb 4, 2020, 11:35:42 AM2/4/20
to
In C++20 you will get `std::source_location` to do the info collection
for you. Usage is as a defaulted argument of e.g. a `dprint` function.

<url: https://en.cppreference.com/w/cpp/utility/source_location>

Unfortunately they forgot to make it safe to copy so it can't reasonably
be used to carry information in an exception. But, since it uses the
standard library's license to employ magic outside the normal rules, it
is or will be great for doing the collecting without macros.


- Alf

Paavo Helde

unread,
Feb 4, 2020, 1:12:53 PM2/4/20
to
On 4.02.2020 18:35, Alf P. Steinbach wrote:
> In C++20 you will get `std::source_location` to do the info collection
> for you. Usage is as a defaulted argument of e.g. a `dprint` function.
>
> <url: https://en.cppreference.com/w/cpp/utility/source_location>
>
> Unfortunately they forgot to make it safe to copy so it can't reasonably
> be used to carry information in an exception.

The above link says it is CopyConstructible and CopyAssignable, and "It
is intended that source_location has a small size and can be copied
efficiently."

Seems "safe to copy" for me.




James Kuyper

unread,
Feb 4, 2020, 4:15:01 PM2/4/20
to
On 2/4/20 11:35 AM, Alf P. Steinbach wrote:
...
> In C++20 you will get `std::source_location` to do the info collection
> for you. Usage is as a defaulted argument of e.g. a `dprint` function.
>
> <url: https://en.cppreference.com/w/cpp/utility/source_location>
>
> Unfortunately they forgot to make it safe to copy

CopyConstructible, CopyAssignable, and "can be copied efficiently" would
seem to cover all the bases. What did they leave out?

"It is unspecified whether the copy/move constructors and the copy/move
assignment operators of source_location are trivial and/or constexpr.",
but I don't see how that would be a big problem (it could be a small
one, in some contexts).

Alf P. Steinbach

unread,
Feb 4, 2020, 4:40:11 PM2/4/20
to
Move constructor is noexcept. Copy constructor is not. :(

<url:
https://en.cppreference.com/w/cpp/utility/source_location/source_location>

Standard exceptions guarantee noexcept copying, so one wouldn't want to
break that reasonably expected guarantee in a custom exception class.
Though it would be technically permitted.


- Alf


Alf P. Steinbach

unread,
Feb 4, 2020, 4:43:08 PM2/4/20
to
Forgot to mention, how do you make a noexcept copyable string value
class very easily?

Just use a `std::runtime_error` to carry the value.

It uses an otherwise very hidden safe to copy string class. I would have
preferred to have that class exposed by the standard library. Alas.


- Alf

Paavo Helde

unread,
Feb 4, 2020, 5:07:56 PM2/4/20
to
Ah, now I see what you meant by "not safe to copy". Could not figure it
out by the previous post.

Well, one can always add a try-catch block and fall back to not have
source_location info in the presumably *very* unlikely case the
source_location copy will throw. A bit cumbersome, yes.

Paavo Helde

unread,
Feb 4, 2020, 5:26:13 PM2/4/20
to
On 4.02.2020 23:42, Alf P. Steinbach wrote:
> On 04.02.2020 22:39, Alf P. Steinbach wrote:
>>
>> Standard exceptions guarantee noexcept copying, so one wouldn't want
>> to break that reasonably expected guarantee in a custom exception
>> class. Though it would be technically permitted.
>
> Forgot to mention, how do you make a noexcept copyable string value
> class very easily?

Been there, done that. Not so easily, and not so sure if it was worth that.

The only exception scenario in string copying is memory exhaustion.
Nowadays I would just silence this and return a static string like
"memory exhausted" from what() if copying failed.

In my experience, if the computer has consumed up all its memory so that
copying of an error message is not possible, then already half of active
programs have crashed and the system has been slowed down to crawl from
which it will not recover without restart. There would not be much point
to try to copy my error message.

Or, with another kind of OS, the culprit program (typically mine) would
already have been killed by the OOM killer and the situation would not
occur.

Keith Thompson

unread,
Feb 4, 2020, 5:39:35 PM2/4/20
to
Paavo Helde <myfir...@osa.pri.ee> writes:
> On 4.02.2020 23:42, Alf P. Steinbach wrote:
>> On 04.02.2020 22:39, Alf P. Steinbach wrote:
>>>
>>> Standard exceptions guarantee noexcept copying, so one wouldn't want
>>> to break that reasonably expected guarantee in a custom exception
>>> class. Though it would be technically permitted.
>>
>> Forgot to mention, how do you make a noexcept copyable string value
>> class very easily?
>
> Been there, done that. Not so easily, and not so sure if it was worth that.
>
> The only exception scenario in string copying is memory
> exhaustion. Nowadays I would just silence this and return a static
> string like "memory exhausted" from what() if copying failed.

How is returning incorrect data (in this case, the string "memory
exhausted") better than, say, terminating the program?

[...]

> In my experience, if the computer has consumed up all its memory so
> that copying of an error message is not possible, then already half of
> active programs have crashed and the system has been slowed down to
> crawl from which it will not recover without restart. There would not
> be much point to try to copy my error message.
>
> Or, with another kind of OS, the culprit program (typically mine)
> would already have been killed by the OOM killer and the situation
> would not occur.

The risk I have in mind is that, even though the system might be on the
verge of falling over, your program might still make use of that
meaningless "memory exhausted" string as if it were valid data, with
arbitrarily bad results.

As I recall, treating an error message as data is part of what led to
the Ariane 5 failure.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Paavo Helde

unread,
Feb 4, 2020, 6:13:45 PM2/4/20
to
On 5.02.2020 0:39, Keith Thompson wrote:
> Paavo Helde <myfir...@osa.pri.ee> writes:
>> On 4.02.2020 23:42, Alf P. Steinbach wrote:
>>> On 04.02.2020 22:39, Alf P. Steinbach wrote:
>>>>
>>>> Standard exceptions guarantee noexcept copying, so one wouldn't want
>>>> to break that reasonably expected guarantee in a custom exception
>>>> class. Though it would be technically permitted.
>>>
>>> Forgot to mention, how do you make a noexcept copyable string value
>>> class very easily?
>>
>> Been there, done that. Not so easily, and not so sure if it was worth that.
>>
>> The only exception scenario in string copying is memory
>> exhaustion. Nowadays I would just silence this and return a static
>> string like "memory exhausted" from what() if copying failed.
>
> How is returning incorrect data (in this case, the string "memory
> exhausted") better than, say, terminating the program?

Not much, typically. However, most C++ code resides in various
libraries, and a library should not decide on terminating the program on
its own, this should be the privilege of the main program.

> [...]
>
>> In my experience, if the computer has consumed up all its memory so
>> that copying of an error message is not possible, then already half of
>> active programs have crashed and the system has been slowed down to
>> crawl from which it will not recover without restart. There would not
>> be much point to try to copy my error message.
>>
>> Or, with another kind of OS, the culprit program (typically mine)
>> would already have been killed by the OOM killer and the situation
>> would not occur.
>
> The risk I have in mind is that, even though the system might be on the
> verge of falling over, your program might still make use of that
> meaningless "memory exhausted" string as if it were valid data, with
> arbitrarily bad results.
>
> As I recall, treating an error message as data is part of what led to
> the Ariane 5 failure.

Right, like the doctor said, don't do that if it hurts. I.e. do not
treat an error message as data. It might change whenever someone feels
he can word the message better, and will certainly change when the
program is translated to French.

If the error message is there just for human information, it can't do
much harm, especially in the stage where the machine has become
unresponsive anyway.

My exception classes always contain an additional numeric error code
which is meant for programmatic consumption. Copying this integer does
not involve dynamic memory allocation, so there would be no danger of
exceptions when copying that.

Juha Nieminen

unread,
Feb 5, 2020, 2:19:17 AM2/5/20
to
James Kuyper <james...@alumni.caltech.edu> wrote:
> On 2/4/20 11:35 AM, Alf P. Steinbach wrote:
> ...
>> In C++20 you will get `std::source_location` to do the info collection
>> for you. Usage is as a defaulted argument of e.g. a `dprint` function.
>>
>> <url: https://en.cppreference.com/w/cpp/utility/source_location>
>>
>> Unfortunately they forgot to make it safe to copy
>
> CopyConstructible, CopyAssignable, and "can be copied efficiently" would
> seem to cover all the bases. What did they leave out?

I think there's a difference between "can be copied" and "safe to copy".
In this case it might not be considered "safe to copy" if copying may
throw an exception.

Keith Thompson

unread,
Feb 5, 2020, 3:21:20 AM2/5/20
to
Paavo Helde <myfir...@osa.pri.ee> writes:
> On 5.02.2020 0:39, Keith Thompson wrote:
>> Paavo Helde <myfir...@osa.pri.ee> writes:
[...]
>>> The only exception scenario in string copying is memory
>>> exhaustion. Nowadays I would just silence this and return a static
>>> string like "memory exhausted" from what() if copying failed.
>>
>> How is returning incorrect data (in this case, the string "memory
>> exhausted") better than, say, terminating the program?
>
> Not much, typically. However, most C++ code resides in various
> libraries, and a library should not decide on terminating the program
> on its own, this should be the privilege of the main program.

And returning "memory exhausted" doesn't give the main program enough
information to decide that it should terminate.

[...]

>> The risk I have in mind is that, even though the system might be on the
>> verge of falling over, your program might still make use of that
>> meaningless "memory exhausted" string as if it were valid data, with
>> arbitrarily bad results.
>>
>> As I recall, treating an error message as data is part of what led to
>> the Ariane 5 failure.
>
> Right, like the doctor said, don't do that if it hurts. I.e. do not
> treat an error message as data. It might change whenever someone feels
> he can word the message better, and will certainly change when the
> program is translated to French.

And how is the caller of a string copying function to know that the
"memory exhausted" string it returns is an error message rather than
data?

> If the error message is there just for human information, it can't do
> much harm, especially in the stage where the machine has become
> unresponsive anyway.
>
> My exception classes always contain an additional numeric error code
> which is meant for programmatic consumption. Copying this integer does
> not involve dynamic memory allocation, so there would be no danger of
> exceptions when copying that.

Sure, if you have *some* out-of-band way to signal errors (not
necessarily exceptions), you'll use that rather than returning
"memory exhausted" as data. Depending on how you represent strings, a
null pointer might make sense.

Robert Wessel

unread,
Feb 5, 2020, 5:19:43 AM2/5/20
to
I'm a little puzzled why this might throw an exception during a copy,
or what case the standard appears to be catering to by allowing one.
The obvious implementation of the structure would be two integers and
two pointers to constant strings, or a single pointer to a constant
structure containing those four items in some fashion.

Sure, I can imaging storing one or both two strings as part of the
structure, but why on earth would anyone do that?

Paavo Helde

unread,
Feb 5, 2020, 5:56:48 AM2/5/20
to
On 5.02.2020 10:20, Keith Thompson wrote:
> Paavo Helde <myfir...@osa.pri.ee> writes:
>> On 5.02.2020 0:39, Keith Thompson wrote:
>>> Paavo Helde <myfir...@osa.pri.ee> writes:
> [...]
>>>> The only exception scenario in string copying is memory
>>>> exhaustion. Nowadays I would just silence this and return a static
>>>> string like "memory exhausted" from what() if copying failed.
>>>
>>> How is returning incorrect data (in this case, the string "memory
>>> exhausted") better than, say, terminating the program?
>>
>> Not much, typically. However, most C++ code resides in various
>> libraries, and a library should not decide on terminating the program
>> on its own, this should be the privilege of the main program.
>
> And returning "memory exhausted" doesn't give the main program enough
> information to decide that it should terminate.

That's right, and it is not clear at all the main program should
terminate. The original exception was raised not because of memory
exhaustion (otherwise it would be a std::bad_alloc), but because of
something else. The reaction should depend on the exception dynamic type
and potentially on any extra info it carries, instead of the (inherently
fragile) error message.

Even if there is a std::bad_alloc exception, it does not mean that
something is so bad the program should terminate. Maybe the user just
wanted to read in a really huge image and a 10 GB memory allocation
failed. A failure of such memory allocation request has no ill effect on
the OS or program state, the program can just inform user this image
cannot be loaded at the moment.


>
> [...]
>
>>> The risk I have in mind is that, even though the system might be on the
>>> verge of falling over, your program might still make use of that
>>> meaningless "memory exhausted" string as if it were valid data, with
>>> arbitrarily bad results.
>>>
>>> As I recall, treating an error message as data is part of what led to
>>> the Ariane 5 failure.
>>
>> Right, like the doctor said, don't do that if it hurts. I.e. do not
>> treat an error message as data. It might change whenever someone feels
>> he can word the message better, and will certainly change when the
>> program is translated to French.
>
> And how is the caller of a string copying function to know that the
> "memory exhausted" string it returns is an error message rather than
> data?

Such static string would not be returned from a string copying function,
but from the exception class what(). This would probably mean some
nullptr stored in the exception object, or something.

The point I wanted to make is really simple: if the system has run out
of memory so seriously that an error message cannot be copied, then it
most probably does not matter any more which error message it was, and
thus there is no need to invent extra clever schemes for trying to
preserve it.

>
>> If the error message is there just for human information, it can't do
>> much harm, especially in the stage where the machine has become
>> unresponsive anyway.
>>
>> My exception classes always contain an additional numeric error code
>> which is meant for programmatic consumption. Copying this integer does
>> not involve dynamic memory allocation, so there would be no danger of
>> exceptions when copying that.
>
> Sure, if you have *some* out-of-band way to signal errors (not
> necessarily exceptions), you'll use that rather than returning
> "memory exhausted" as data. Depending on how you represent strings, a
> null pointer might make sense.

An exception object can store more data than just a string or a string
pointer. I would not call this extra data out-of-band.

Ned Latham

unread,
Feb 5, 2020, 6:22:48 AM2/5/20
to
Keith Thompson wrote:
> Paavo Helde writes:
> > Keith Thompson wrote:
> > > Paavo Helde writes:
> [...]
> > > > The only exception scenario in string copying is memory
> > > > exhaustion. Nowadays I would just silence this and return a static
> > > > string like "memory exhausted" from what() if copying failed.
> > >
> > > How is returning incorrect data (in this case, the string "memory
> > > exhausted") better than, say, terminating the program?
> >
> > Not much, typically. However, most C++ code resides in various
> > libraries, and a library should not decide on terminating the program
> > on its own, this should be the privilege of the main program.
>
> And returning "memory exhausted" doesn't give the main program enough
> information to decide that it should terminate.

It should do. The caller knows where it issued the call and with what
parameters. Good way to keep bugs out of code.

> [...]
>
> > > The risk I have in mind is that, even though the system might be on
> > > the verge of falling over, your program might still make use of that
> > > meaningless "memory exhausted" string as if it were valid data, with
> > > arbitrarily bad results.
> > >
> > > As I recall, treating an error message as data is part of what led to
> > > the Ariane 5 failure.
> >
> > Right, like the doctor said, don't do that if it hurts. I.e. do not
> > treat an error message as data. It might change whenever someone feels
> > he can word the message better, and will certainly change when the
> > program is translated to French.
>
> And how is the caller of a string copying function to know that the
> "memory exhausted" string it returns is an error message rather than
> data?

That depends on your string library. Mine always returns either a string
class object or an unsinged int. In both cases a zero return indicates
an error, and the caller can inspect the string for more detail on the
error. The language of that depends on the library, not the data.

----snip----

Keith Thompson

unread,
Feb 5, 2020, 3:15:50 PM2/5/20
to
Paavo Helde <myfir...@osa.pri.ee> writes:
> On 4.02.2020 23:42, Alf P. Steinbach wrote:
>> On 04.02.2020 22:39, Alf P. Steinbach wrote:
>>> Standard exceptions guarantee noexcept copying, so one wouldn't want
>>> to break that reasonably expected guarantee in a custom exception
>>> class. Though it would be technically permitted.
>>
>> Forgot to mention, how do you make a noexcept copyable string value
>> class very easily?
>
> Been there, done that. Not so easily, and not so sure if it was worth that.
>
> The only exception scenario in string copying is memory
> exhaustion. Nowadays I would just silence this and return a static
> string like "memory exhausted" from what() if copying failed.
[...]

Please disregard most of what I've written in this thread.
I misunderstood what Paavo was saying. I forgot that "what()" is
the name of a function that returns information about an exception,
and thought that he was talking about having the string copying
function itself return the string "memory exhausted". I should
have read more carefully. (The term "noexcept" also threw me off
from considering exception semantics.)

Sorry about the noise.

Keith Thompson

unread,
Feb 5, 2020, 3:16:51 PM2/5/20
to
Paavo Helde <myfir...@osa.pri.ee> writes:
[...]
> Such static string would not be returned from a string copying
> function, but from the exception class what(). This would probably
> mean some nullptr stored in the exception object, or something.
[...]

And that's the part that I misunderstood. See my reply upthread.
0 new messages