Monday, June 15, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 6 topics

Doug Mika <dougmmika@gmail.com>: Jun 15 10:48AM -0700

I will admit, I've tried to understand as precisely as possible what constexpr does. I think I have an idea, but I know it's not what it should be. So perhaps asking the following will further shed light on what constexpr does:
 
static_assert(100000<numeric_limits<int>::max(),"small ints!");
 
and then it says:
"Note that the second assert (only) works because numeric_limits<int>::max() is a constexpr function"
 
Can someone quickly explain why that is so?
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jun 15 07:58PM +0200

On 15.06.15 19.48, Doug Mika wrote:
 
> and then it says:
> "Note that the second assert (only) works because numeric_limits<int>::max() is a constexpr function"
 
> Can someone quickly explain why that is so?
 
Because the function is not yet compiled it cannot be called.
Furthermore it might be non deterministic. I.e. it is not clear whether
the assertion should fail or not. Think about cross compilation.
 
 
Marcel
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 15 01:58PM -0400

On 6/15/2015 1:48 PM, Doug Mika wrote:
> I will admit, I've tried to understand as precisely as possible what
constexpr does. I think I have an idea, but I know it's not what it
should be. So perhaps asking the following will further shed light on
what constexpr does:
 
> static_assert(100000<numeric_limits<int>::max(),"small ints!");
 
> and then it says:
> "Note that the second assert (only) works because
numeric_limits<int>::max() is a constexpr function"
 
> Can someone quickly explain why that is so?
 
Why WHAT is so? Next time be more specific please.
 
The requirement is that the first argument of 'static_assert' shall be a
constant-expression. If you try using any function that is not declared
'constexpr' in an expression, the compiler will refuse it. In your
example, the expression 100000 < blah, the 'blah' portion is a call to a
function declared 'constexpr', so the entire expression becomes constant
expression (calculated in compile-time).
 
If that's not what you were asking, rephrase your question.
 
V
--
I do not respond to top-posted replies, please don't ask
legalize+jeeves@mail.xmission.com (Richard): Jun 15 06:50PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
>"Note that the second assert (only) works because
>numeric_limits<int>::max() is a constexpr function"
 
>Can someone quickly explain why that is so?
 
Ask yourself "What does static_assert do?"
 
Answer: "Performs compile-time assertion checking."
<http://en.cppreference.com/w/cpp/language/static_assert>
 
What does this imply? It implies that the arguments to static_assert
must be evaluated at compile-time and not at runtime.
 
What are the arguments to static_assert?
 
1. 100000<numeric_limits<int>::max() aka
100000 < numeric_limits<int>::max()
2. "small ints!"
 
The 2nd argument is just the diagnostic message to be printed when the
static assertion fails. The first argument must be something that can
be evaluated at compile-time, so let's look at it more carefully.
 
It is an application of operator< to 100000 and
numeric_limits<int>::max(). 100000 is a constant, so no problem there.
numeric_limits<int>::max() is an invocation of the max member function
on the class numeric_limits<int>. numeric_limits<int> is known at
compile time, so no problem there. All that's left is the max member
function. This function must be declared constexpr so that it can be
evaluated at compile time, otherwise it would be a compilation error.
 
template <typename T>
struct foo
{
T max();
};
 
template<>
struct foo<int>
{
static int max() { return 10; }
};
 
static_assert(100000 < foo<int>::max(), "whoops");
 
g++ -c -g -std=c++0x /tmp/a.cpp
/tmp/a.cpp:13:1: error: non-constant condition for static assertion
static_assert(100000 < foo<int>::max(), "whoops");
^
/tmp/a.cpp:13:38: error: call to non-constexpr function 'static int
foo<int>::max()'
static_assert(100000 < foo<int>::max(), "whoops");
^
 
We can fix this by making the function constexpr, allowing the compiler
to use it at compile time:
 
template <typename T>
struct foo
{
T max();
};
 
template<>
struct foo<int>
{
static constexpr int max() { return 10; }
};
 
static_assert(100000 < foo<int>::max(), "whoops");
 
g++ -c -g -std=c++0x /tmp/a.cpp
/tmp/a.cpp:13:1: error: static assertion failed: whoops
static_assert(100000 < foo<int>::max(), "whoops");
^
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jun 15 06:52PM

[Please do not mail me a copy of your followup]
 
Marcel Mueller <news.5.maazl@spamgourmet.org> spake the secret code
>numeric_limits<int>::max() is a constexpr function"
 
>> Can someone quickly explain why that is so?
 
>Because the function is not yet compiled it cannot be called.
 
Wrong.
 
>Furthermore it might be non deterministic. I.e. it is not clear whether
>the assertion should fail or not. Think about cross compilation.
 
Also wrong.
 
Cross-compilation and "not yet compiled" have nothing to do with
constexpr and static_assert.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 05:14PM +0100

On 15/06/2015 11:11, gwowen wrote:
 
>> /Flibble
 
> Wait, weren't you recommending size_t a minute ago?
 
> But "their size and value range can differ from one implementation to the next" so size_t must, by this logic (and way I say logic, I am using the word quite wrongly) be unsafe.
 
Ah but std::size_t is a special case: it should only be used in the
context of allocations or where it is aliased by a container::size_type
when indexing for example. The guarantees we have for std::size_t
within the context of what it is supposed to be used for make it quite
safe. If you are using std::size_t in other contexts where its size or
value range matter then you are again writing unsafe code and are doing
it wrong (TM).
 
/Flibble
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 05:26PM +0100

On 13/06/2015 19:21, Ben Bacarisse wrote:
> using these types is neither non-portable nor unsafe. (They can, of
> course, be *used* in unsafe and non-portable ways but it's hard to think
> of type that can't be so abused.)
 
It isn't an overstatement at all. If using 'int', 'short' and 'long' is
unsafe in safety critical domains then it is also unsafe in *any* domain
(even if the worst that can happen is losing a life in a video game).
To quote the MISRA C++ coding standard:
 
"typedefs that indicate size and signedness should be used in place of
the basic numerical types."
 
/Flibble
Francis Glassborow <francis.glassborow@btinternet.com>: Jun 15 11:22AM -0600

On 15/06/2015 14:13, David Brown wrote:
 
> We should use the most appropriate type for the task in hand (which
> could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
 
> Personally, I have very little use of "short" or "long", however.
 
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.
 
And where I need 64 bits the (ugly) long long int meets my need.
 
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
 
 
I agree that short is pretty useless these days. It would have made more
sense if it had been an exact 16-bit integer type.
 
Francis
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Lynn McGuire <lmc@winsim.com>: Jun 15 11:54AM -0500

On 6/13/2015 11:43 AM, Mr Flibble wrote:
 
> or
 
> auto i = 42u32; // unsigned, 32-bits
 
> /Flibble
 
Int has always been signed and had four sizes for me over the years: 36 bits, 60 bits, 32 bits and 16 bits.
 
Lynn
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 06:11PM +0100

On 15/06/2015 18:22, Francis Glassborow wrote:
> least 32-bits, so why would I not use that when I need a 32-bit integer?
> That is why int32_t better? Note that on systems with 32-bit int, long
> int is usually also 32 bits.
 
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
 
 
> And where I need 64 bits the (ugly) long long int meets my need.
 
> If I use real types I do not have to worry about places where the
> behaviour varies according to the underlying type (most commonly i/o in C)
 
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.
 
/Flibble
woodbrian77@gmail.com: Jun 15 10:50AM -0700

On Monday, June 15, 2015 at 12:11:11 PM UTC-5, Mr Flibble wrote:
> *dangerous behaviour*. If you want a type that behaves like 'int' then
> you should be explicit about it in your code by using 'int_fast16_t' but
> absolute care must be taken when using such variable types.
 
In some cases I would use long or int_fast32_t rather than int,
but the system calls I'm using specify int in their interface.
 
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
 
So there's not much I can do about it at this time.
 
Brian
Ebenezer Enterprises - Smile. G-d loves you and so do I.
http://webEbenezer.net
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 01:02PM -0600

On 15/06/2015 18:22, Francis Glassborow wrote:
> least 32-bits, so why would I not use that when I need a 32-bit integer?
> That is why int32_t better? Note that on systems with 32-bit int, long
> int is usually also 32 bits.
 
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
 
 
> And where I need 64 bits the (ugly) long long int meets my need.
 
> If I use real types I do not have to worry about places where the
> behaviour varies according to the underlying type (most commonly i/o in C)
 
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.
 
/Flibble
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
legalize+jeeves@mail.xmission.com (Richard): Jun 15 06:33PM

[Please do not mail me a copy of your followup]
 
Lynn McGuire <lmc@winsim.com> spake the secret code
 
>Int has always been signed and had four sizes for me over the years: 36
>bits,
 
DECsystem-10/20?
 
>60 bits,
 
CDC Cyber?
 
>32 bits and 16 bits.
 
Well, these could be almost anything from x86 to PDP-11 to VAX to
embedded MIPS RISC CPU.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Lynn McGuire <lmc@winsim.com>: Jun 15 01:45PM -0500

On 6/15/2015 1:33 PM, Richard wrote:
 
>> 32 bits and 16 bits.
 
> Well, these could be almost anything from x86 to PDP-11 to VAX to
> embedded MIPS RISC CPU.
 
The UNIVAC 1108 was a 36 bit word, 6 byte word machine.
 
Lynn
legalize+jeeves@mail.xmission.com (Richard): Jun 15 06:51PM

[Please do not mail me a copy of your followup]
 
Lynn McGuire <lmc@winsim.com> spake the secret code
 
>> Well, these could be almost anything from x86 to PDP-11 to VAX to
>> embedded MIPS RISC CPU.
 
>The UNIVAC 1108 was a 36 bit word, 6 byte word machine.
 
Ah.
 
Did I guess the 60-bit machine right?
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Paul <pepstein5@gmail.com>: Jun 15 10:02AM -0700

A problem on the web asks to alternate members from two lists. For precise wording, see the comments in the posted code below. I'm trying to generalize by saying the lists can be of any type. I can't quite get this to work although I feel I'm on the right lines. I'm not surprised it doesn't compile but I'm not sure what the best fix is. Thank you very much for your advice.
 
Paul
 
/* Problem 2
Write a function that combines two lists by alternatingly taking elements. For example: given the two lists [a, b, c] and [1, 2, 3], the function should return [a, 1, b, 2, c, 3].
A difficult technicality is that it seems that the elements can come from different types -- ints and chars.
Problem doesn't say how to handle the case where lists have different lengths. Will simply add on the remaining elements.
*/
 
template<typename elementType1, typename elementType2>
union twoTypes
{
elementType1 type1;
elementType2 type2;
};
 
template <typename elementType1, typename elementType2>
std::vector <twoTypes <elementType1, elementType2> > amalgamate(const std::vector<elementType1>& type1, const std::vector<elementType2>& type2)
{
std::vector <twoTypes <elementType1, elementType2> > results;
int min = std::min(type1.size(), type2.size());
int max = std::max(type1.size(), type2.size());
 
for(int i = 0; i < min; ++i)
{
results.push_back(type1[i]);
results.push_back(type2[i]);
}
 
for(int i = min + 1; i < max; ++i)
results.push_back( i < type1.size() ? type1[i] : type2[i]);
 
return results;
}
 
void testProblem2()
{
const std::vector<char> firstVec = {'a', 'b', 'c'};
const std::vector<int> secondVec = {1, 2, 3};
const std::vector<int> differentSizeVec = {1,2,3,4,5};
std::vector<twoTypes<char, int> > results = amalgamate(firstVec, secondVec);
std::cout << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << secondVec.size() << " numbers gives a result as follows ";
 
for (auto i : results)
std::cout << std::endl << i;
 
results = amalgamate(firstVec, differentSizeVec);
std::cout << std::endl << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << differentSizeVec.size() << " numbers gives a result as follows ";
 
for (auto i : results)
std::cout << std::endl << i;
}
pauldanielepstein@gmail.com: Jun 15 10:51AM -0700

On Monday, June 15, 2015 at 6:02:24 PM UTC+1, Paul wrote:
 
> for (auto i : results)
> std::cout << std::endl << i;
> }
 
Oh, just spotted an error. i should go from min and not jump to min + 1. But I'm still confused on the larger point.
 
Thanks.
 
Paul
Barry Schwarz <schwarzb@dqel.com>: Jun 15 11:24AM -0700

On Mon, 15 Jun 2015 10:02:15 -0700 (PDT), Paul <pepstein5@gmail.com>
wrote:
 
> in the posted code below. I'm trying to generalize by saying the lists can be of any type. I can't quite get
>this to work although I feel I'm on the right lines. I'm not surprised it doesn't compile but I'm not sure what
>the best fix is. Thank you very much for your advice.
 
Always show the compiler diagnostics.
 
> {
> results.push_back(type1[i]);
> results.push_back(type2[i]);
 
results is a vector of twoTypes. You are not pushing a twoTypes
object onto it but an elementType1 (or 2) object.
 
You need code to define a union right after defining the vector,
similar to
twoTypes myUnion;
and then code to assign each element to the union and push the union
onto results, similar to
myUnion.type1 = type1[i];
results.push_back(myUnion);
// ditto for type2
 
> }
 
> for(int i = min + 1; i < max; ++i)
> results.push_back( i < type1.size() ? type1[i] : type2[i]);
 
Same problem here.
 
> std::cout << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << secondVec.size() << " numbers gives a result as follows ";
 
> for (auto i : results)
> std::cout << std::endl << i;
 
What does it mean to try to insert a union into the stream. Which
member of the union should be printed? You need something like
for (int i = 0; i < results.size(); i++)
{
if (i % 2 == 0)
cout << endl << results[i].type1;
else
cout << endl << results[i].type2;
}
 
> std::cout << std::endl << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << differentSizeVec.size() << " numbers gives a result as follows ";
 
> for (auto i : results)
> std::cout << std::endl << i;
 
Ditto
 
 
--
Remove del for email
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 01:33PM -0500

Paul <pepstein5@gmail.com> wrote in
> elementType1 type1;
> elementType2 type2;
> };
 
Your union is very dumb one and does not know which type it is holding at
any moment. You should put it inside a class, together with a type flag
or something, and add a custom operator<< for stream output which
interpretes the type flag and outputs the correct union member.
 
Beware that unions are quite tricky to get working properly, especially
with non-POD types (C++11 allows non-POD-s in unions, but it's still
tricky). Are you sure that the exercise is not meant for some other more
loosely typed language than C++?
 
hth
Paavo
Paul <pepstein5@gmail.com>: Jun 15 11:40AM -0700

On Monday, June 15, 2015 at 7:33:43 PM UTC+1, Paavo Helde wrote:
> with non-POD types (C++11 allows non-POD-s in unions, but it's still
> tricky). Are you sure that the exercise is not meant for some other more
> loosely typed language than C++?
 
I agree that I'm trying something much more ambitious than what the problem-poser intended. I think that the intention is that everything should be a char. So [1, 2, 3] is the vector<char> {'1', '2', '3'}. Then the problem is really easy.
 
Thanks for your advice.
 
Paul
Doug Mika <dougmmika@gmail.com>: Jun 15 10:13AM -0700

On Friday, June 12, 2015 at 10:50:36 AM UTC-5, Doug Mika wrote:
> 1)How would this sort template look if we were to not have using Iter = Iterator_type<C>;? What does this line do? - I have never seen it used in this context.
> 2)What is Iterator_type and Iterator_category? I searched for these on www.cplusplus.com but found nothing that would make it clear.
 
> Thanks to all for reading something this long.
 
I appreciate everyone's patience: so what you're trying to tell me is that the following is the definition of Iterator_type:
 
template<typename C>
using Iterator_type = typename C::iterator; //C's iterator type
 
Ok, I've heard of template functions, and template classes, but what would something like this be? A template followed by the "using" keyword? Could someone define what these two lines do, as precisely as possible?
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 15 01:20PM -0400

On 6/15/2015 1:13 PM, Doug Mika wrote:
>[..]
> I appreciate everyone's patience: so what you're trying to tell me
> is
that the following is the definition of Iterator_type:
> would something like this be? A template followed by the "using"
> keyword? Could someone define what these two lines do, as precisely
> as possible?
 
It's called "an alias template", it essentially declares a name that can
act as a template-id. Alias templates are used to reduce the number of
template arguments that are needed to be specified thus narrowing down
the set of generated types. For instance, you can define your own
custom allocator to be used with all possible vectors you might want to
define later, and then say
 
template<class T>
using myvector = std::vector<T, myspecialallocator<T>>;
 
Then, when you say
 
myvector<int> vi;
 
it will be the same as saying
 
std::vector<int, myspecialallocator<int>> vi;
 
. It's kind of a typedef, but for templates.
 
V
--
I do not respond to top-posted replies, please don't ask
legalize+jeeves@mail.xmission.com (Richard): Jun 15 06:32PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
 
>Ok, I've heard of template functions, and template classes, but what
>would something like this be? A template followed by the "using" keyword?
>Could someone define what these two lines do, as precisely as possible?
 
It's called a type alias and is new to C++11:
 
<http://en.cppreference.com/w/cpp/language/type_alias>
 
It is similar to, but more general than, typedef.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Paul <pepstein5@gmail.com>: Jun 15 10:27AM -0700

On Saturday, June 13, 2015 at 9:48:07 PM UTC+1, Ben Bacarisse wrote:
> explicitly.
 
> --
> Ben.
 
Ok. It's clearer now. Thanks a lot.
 
Paul
Paul <pepstein5@gmail.com>: Jun 15 10:26AM -0700

On Sunday, June 14, 2015 at 10:39:05 PM UTC+1, Paul N wrote:
> > The return type of operator= is a reference to the invoking object, so as to allow chained assignments a=b=c. Though it would seem that the return type should be a const reference, so as to disallow nonsense such as (a=b)=c, that expression is in fact allowed in C++ even for integer types. Hence, the reference return type (rather than the const reference return type) is customarily used but is not strictly required by the language specification.
> > END QUOTE
 
> I think you're reading a bit too much into it. If operator= returned, say, void, then you wouldn't be able to chain assignments. So you need to do something else. Returning a reference is one possibility, but I don't think the passage actually says that it's the only possible one. Returning a reference is more usual than returning a value as it is likely to be more efficient.
 
Thanks.
 
Yes, that's what the author meant. He also accepts my criticism of the wording, and will be clearer in future editions.
 
Paul
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: