Tuesday, November 6, 2018

Digest for comp.lang.c++@googlegroups.com - 16 updates in 5 topics

David Brown <david.brown@hesbynett.no>: Nov 06 04:08PM +0100

On 06/11/18 15:49, Rick C. Hodgin wrote:
> size in bytes, and the bitsizeof() to return the size in bits, and
> that will be globally, not just on bitfield structs or members.
 
> Good day, David.
 
Adding a "bitsizeof" operator for bit-fields seems reasonable enough. I
don't see a lot of potential use for it, but I know we have very
different opinions on that sort of thing (I want to know a feature is
very useful before adding it, you prefer to add early and let the user
decide if they want to use it).
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 07:32AM -0800

On Tuesday, November 6, 2018 at 10:08:16 AM UTC-5, David Brown wrote:
> different opinions on that sort of thing (I want to know a feature is
> very useful before adding it, you prefer to add early and let the user
> decide if they want to use it).
 
Yes, because I'm not arrogant enough to think I have all the
answers to all of the coding scenarios. I want to empower each
developer to be able to reach into the vast tookbox and use the
tools they need.
 
People who trim trees drive similar trucks to those who install
power lines, cable and Internet, yet I bet each of those trucks
that look outwardly similar have vastly different tools in the
toolboxes.
 
For different types of application design, it's like that. Some
trim trees, some install power lines, and some work with the el-
ectronic infrastructure and fiber optics to make TV and Internet
work.
 
It comes down to the individual at work doing their job, even
though many of the tools will be similar, the specific details
give aid and benefit where needed, and can be largely ignored
otherwise.
 
--
Rick C. Hodgin
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 06 05:41PM

On 06/11/2018 14:49, Rick C. Hodgin wrote:
[snip]
> I just happen to know I'm right.
 
And Satan invented fossils, yes?
 
/Flibble
 
--
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 09:51AM -0800

On Tuesday, November 6, 2018 at 12:42:00 PM UTC-5, Mr Flibble wrote:
> [snip]
> > I just happen to know I'm right.
 
> And Satan invented fossils, yes?
 
No. He invented the lie that says he invented fossils, and
then spread that lie around under false pretenses, designed
entirely to deceive people who will not seek the truth under
any circumstance whatsoever.
 
It breaks my heart, Leigh. If I knew how to reach you in a
way which would reach you ... I'd do it.
 
--
Rick C. Hodgin
jameskuyper@alumni.caltech.edu: Nov 06 10:28AM -0800

On Tuesday, November 6, 2018 at 4:50:07 AM UTC-5, David Brown wrote:
...
> saying that the "addressable storage unit" here has to be of the size
> and type of the bit-field's type - indeed, "An implementation may
> allocate any addressable storage unit large enough to hold a bit-field".
 
The only requirements on the "addressable storage unit" are: "If enough
space remains, a bit-field that immediately follows another bit-field in
a structure shall be packed into adjacent bits of the same unit. If
insufficient space remains, whether a bit-field that does not fit is put
into the next unit or overlaps adjacent units is implementation-defined.
The order of allocation of bit-fields within a unit (high-order to low-
order or low-order to high-order) is implementation-defined."
(6.7.2.1p11).
There's no requirement that the size of the unit be documented, nor that
it be the same for different struct types. There's certainly no
requirement that it be connected to the type used to declare a bit-
field.
 
> However, the usefulness of bit-fields for "conforming to externally
> imposed layouts" would be hindered if the implementation did not give
> the programmer control over the sizes here.
 
Strictly speaking, the requirements that the C standard fails to impose
on the layout of structs in particular, and on bit-fields in particular,
make C structs useless, in code intended to be portable, for describing
externally imposed layouts.
I don't approve of this (as shocking as that fact might seem to those
who claim that I worship the holy standard). But this state of affairs
exists because, at the time the first standard was being written,
different compilers implemented different rules for the layout of
structures, and no agreement could be reached to mandate stricter
requirements than the ones we currently have. That state of affairs
continues to the present, and requirements of backwards compatibility
makes it difficult to impose any new restrictions in future versions of
the standard. The best we could hope for is some new way of defining
struct types (or perhaps, something struct-like but using different
syntax) that have layouts more tightly constrained by the standard than
ordinary struct types.
In the mean time, the closest you can get to portable code for
externally-imposed memory layouts, is to mask and shift operations on
the members of arrays of unsigned char.
 
> Older C compilers sometimes had support for only "signed int" and
> "unsigned int" as bit-field types -
 
Those two are the only types that all versions of the standard have
mandated support for - since C99 it also mandates support for _Bool as a
bit-field's type. Implementations are explicitly allowed to support
other integer types, but code that needs to be portable can't take
advantage of that fact.
 
> would have used smaller underlying storage units, while I think more
> modern ones use the type you ask for. But it is, naturally,
> implementation-dependent.
 
It didn't have to be - that's just the way C was defined.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 06 09:41PM +0100

On 06.11.2018 15:01, Öö Tiib wrote:
> | implementation-defined."
 
> Why? Who benefits from such a wasted feature? That could be defined
> to follow order of bytes on platform.
 
Well, the g++ implementation of the now deprecated conversion to/from
UTF-8 in the standard library. Worth noting that Visual C++ screws up in
a different way. So it's perhaps good that it's now deprecated, but
AFAIK there's no replacement. :(
 
 
Cheers!,
 
- Alf
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 06 10:38PM

On 06/11/2018 17:51, Rick C. Hodgin wrote:
[snip]
> No. He invented the lie that says he invented fossils,
[snip]
 
Satan doesn't exist mate.
 
And Satan invented fossils, yes?
 
/Flibble
 
--
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
ram@zedat.fu-berlin.de (Stefan Ram): Nov 06 10:23PM

>What is the best and most standard way to print objects of your
>classes?
 
These actually are two questions:
 
- What is the best /interface/ your class should
support to print its object? and
 
- What is the best /implementation/ of this interface?
 
With regard to the interface, it was, IIRC, Herb Sutter wh
who suggested something like:
 
class example
{ ~~~
 
public:
::std::ostream & print( ::std::ostream & stream )const
{ ~~~ }
 
~~~ }
 
inline ::std::ostream& operator <<
( ::std::ostream & stream, example const & object )
{ return object.print( stream ); }
 
. For the rationales read, IIRC, "class mechanics"
by Herb Sutter (preferably an updated version).
Steve Keller <keller@no.invalid>: Nov 06 06:11PM +0100

What is the best and most standard way to print objects of your
classes? In other people's code I often find something like this:
 
class Foo {
public:
std::string toString() const {
std::ostringstream s;
s << "{..." << /* more items */ << "}";
return s.str();
};
 
class MyEnum {
enum { A, B, C } e;
public:
std::string toString() const {
switch (e) {
case A:
return "A";
case B:
return "B";
case C:
return "C";
}
};
 
void some_other_func(const Foo &f, const MyEnum &e) {
std::cout << f.toString() << ' '
<< e.toString() << std::endl;
}
 
However, I prefer to implement functions that print to std::ostream
directly, instead of writing to std::stringstream, then creating a
string, and then printing the string to an ostream:
 
class Foo {
public:
void print(std::ostream &os) const {
os << "{..." << /* more items */ << "}";
}
};
 
std::ostream &operator<<(std::ostream &os, const Foo &foo) {
foo.print(os);
return os;
}
 
class MyEnum {
enum { A, B, C } e;
public:
void print(std::ostream &os) const {
switch (e) {
case A:
os << "A"; break;
case B:
os << "B"; break;
case C:
os << "C"; break;
}
};
 
std::ostream &operator<<(std::ostream &os, const MyEnum &e) {
e.print(os);
return os;
}
 
void some_other_func(const Foo &f, const MyEnum &e) {
std::cout << f << ' ' << e << std::endl;
}
 
Since I see the first method so often I wonder if there is something wrong
with my solution. Does the above approach have any advantages I don't see?
 
Steve
Paavo Helde <myfirstname@osa.pri.ee>: Nov 06 07:57PM +0200

On 6.11.2018 19:11, Steve Keller wrote:
> std::string toString() const {
 
> However, I prefer to implement functions that print to std::ostream
> directly,
 
The stream approach is architecturally more sound, more flexible and
more customizable. For example, if your object "stringification"
involves floating-point numbers then the toString() function has to
decide how to format the decimal point: by the current locale, always as
'.', etc. When using the stream approach, the client code is assumed to
know what it wants and to imbue the needed locale to the stream.
 
At least this is the intention. In practice the customization
possibilities provided by locales are often far too few and too little
to provide anything better than inconsistencies and grammar errors, so
I'm not sure if they do more good than harm.
 
The strings approach typically avoids all this flexibility and
customizations. This means the result is always in fixed format and the
performance is usually better (string+= won up to 2x in my measurements,
compared to ostringstream<<).
 
So the answer depends on your needs and preferences. Is the printout
meant for humans or for other software? If for humans, is it for a
single person or for many? Is the speed important? Is fixed format
important? Etc.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Nov 06 07:48PM

On Tue, 2018-11-06, Steve Keller wrote:
> s << "{..." << /* more items */ << "}";
> return s.str();
> };
...
 
> However, I prefer to implement functions that print to std::ostream
> directly, instead of writing to std::stringstream, then creating a
> string, and then printing the string to an ostream:
...
 
> Since I see the first method so often I wonder if there is something wrong
> with my solution. Does the above approach have any advantages I don't see?
 
I suspect the first approach is a Java/whatever other language
influence. To me it means working against the intention of the
language (but I don't see it much).
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 06 09:33PM +0100

On 06.11.2018 18:11, Steve Keller wrote:
> s << "{..." << /* more items */ << "}";
> return s.str();
> };
 
This code suffers from non-systematic indentation. Also, please use
spaces, not tabs. The presentation of tabs depends on the software used
to view the message, so tabs can really mess up things.
 
From the string format you've chosen it appears that the purpose of
"print objects of your classes" is tracing and debugging, not
interaction with a user or storing a description from which an equal
object can be reconstituted (serialization and de-serialization).
 
For tracing and debugging involving an iostream's locale machinery and
general inefficiency, is IMHO counter-productive.
 
One could build on `std::to_string`, but that involves the C locale
machinery and forced dynamic allocations for the string buffers. Not
quite as bad as the C++ level, but results that depend on a global
easily modified state, means unpredictable results in general.
 
Happily, C++17 introduced ¹`to_chars`. Unfortunately, (1) there's
apparently no way to predict the required buffer size, except by using
`snprintf`, the design or possibly (but not likely) just its
documentation, is bungled, and (2) the g++'s standard library
implementation libstdc++ ²doesn't yet support `to_chars`.
 
It's not that big a deal to define that kind of functionality, and there
are 3rd party libraries that do, but I think I would assume a locale
that at worst uses mainland European "," instead of ".", and /under that
assumption/ accept the slight performance hit from the C locale stuff
(essentially, replacing any produced ",") and just use `snprintf`:
 
-------------------------------------------------------------------------
#include <algorithm> // std::replace
#include <iterator> // std::size
#include <string> // std::string
#include <stddef.h> // ptrdiff_t
 
namespace cppx
{
template< class A_type > using Type_ = A_type;
 
using Size = ptrdiff_t;
 
template< class Container >
auto n_items( const Container& c )
-> Size
{ return std::size( c ); }
} // namespace cppx
 
namespace my
{
using cppx::n_items, cppx::Type_, cppx::Size;
using std::string, std::replace;
 
// Always returns the number of chars that /would/ be generated on
success.
auto convert_to_text(
const double x,
const Type_<char*> buffer,
const Size buffer_size
)
-> Size
{
const Size n_chars = snprintf( buffer, buffer_size, "%g", x );
if( n_chars <= buffer_size )
{
replace( buffer, buffer + n_chars, ',', '.' );
}
return n_chars;
}
 
auto to_string( const double x, string buffer = string( 16, '\0' ) )
-> string
{
const Size n_chars = convert_to_text( x, buffer.data(),
n_items( buffer ) );
if( n_chars > n_items( buffer ) )
{
buffer.resize( n_chars );
convert_to_text( x, buffer.data(), n_items( buffer ) );
}
return buffer;
}
 
} // namespace my
 
#include <iostream>
auto main()
-> int
{
using namespace std;
cout << my::to_string( 3.14e15 ) << endl;
}
-------------------------------------------------------------------------
 
It shouldn't be difficult to add support for other formats, field width,
precision and whatever.
 
 
> return "C";
> }
> };
 
I guess the intent is to somehow provide client code with three global
static instances of `MyEnum`, corresponding to the three `enum` values.
 
Instead of a `switch`, just use an array of values.
 
auto to_string() const
-> const char*
{
static const Type_<const char*> names[] = {"A", "B", C"};
return names[e];
}
 
By the way, using all uppercase for values runs the risk of inadvertent
text substitution. In C and C++ you can avoid needless work and needless
annoyance by reserving all uppercase identifiers for macros -- and the
few idiomatic other uses such as `T` for template parameter type.
 
 
 
> However, I prefer to implement functions that print to std::ostream
> directly, instead of writing to std::stringstream, then creating a
> string, and then printing the string to an ostream:
 
It's unclear what the "instead of" refers to.
 
You haven't illustrated any such code.
 
 
> foo.print(os);
> return os;
> }
 
This is the conventional way to do things.
 
It scales, it's reasonably type safe, but it's in practice inefficient
/and/ it doesn't handle nationalization well. Better with format
strings. Check out e.g. the Boost Format library.
 
 
> os << "C"; break;
> }
> };
 
Again, better use an array than a `switch`.
 
Note that this approach is good only where the client code wants the
text output to a stream. For that case it's just about as efficient and
clean to use as the `const char*` function I presented above.
 
For any other use it drags in inefficiency and makes the usage unclean.
 
 
> }
 
> Since I see the first method so often I wonder if there is something wrong
> with my solution. Does the above approach have any advantages I don't see?
 
Uhm, don't know.
 
But regarding the "so often", IMO that indicates that you are exposed to
code that is not typical.
 
 
Cheers!,
 
- Alf
 
Notes:
¹ https://en.cppreference.com/w/cpp/utility/to_chars
²
https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2017
red floyd <dont.bother@its.invalid>: Nov 06 02:09PM -0800

On 11/6/2018 12:33 PM, Alf P. Steinbach wrote:
> On 06.11.2018 18:11, Steve Keller wrote:
------------
>         static const Type_<const char*> names[] = {"A", "B", C"};
>         return names[e];
>     }
 
In this individual case, yes, an array works. But remember, enums
do not need to be consecutive, in which case some other mechanism
is required. One size does not fit all.
scott@slp53.sl.home (Scott Lurndal): Nov 06 03:18PM

>> in size.
 
>I hadn't actually read that bit of the thread!
 
>CHAR_BIT is /always/ at least 8, so you are safe there.
 
Wasn't always. 6-bit characters were very common (DEC, Burroughs) a few
decades ago (e.g. at the time C was developed).
Manfred <noname@add.invalid>: Nov 06 07:55PM +0100

On 11/6/2018 4:18 PM, Scott Lurndal wrote:
 
>> CHAR_BIT is /always/ at least 8, so you are safe there.
 
> Wasn't always. 6-bit characters were very common (DEC, Burroughs) a few
> decades ago (e.g. at the time C was developed).
 
But the ISO standard requires CHAR_BIT to be equal or greater than 8.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 06 06:24PM

On 6 Nov 2018 01:50:02 GMT
> | ^~~~~~~~~~~~~
 
> Does this warning make sense for a /non-member/ function?
 
> Also feel free to suggest any improvements to my code!
 
[snip]
 
This warning seems to be concerned with gcc function attributes rather
than the C and C++ keyword 'const'. If so, it signifies that the
function does not read any global data and only depends on its
arguments:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
 
It looks as if you have specifically asked for this "warning" (it isn't
really a warning) with the -Wsuggest-attribute=const compiler flag.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: