- constexpr - 5 Updates
- Avoid 'int' and associates. - 10 Updates
- Help using unions - 5 Updates
- A confusing topic in Stroustrup's book - 3 Updates
- Function pointer syntax - 1 Update
- Confusing passage in C++ book - 1 Update
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:
Post a Comment