"Öö Tiib" <ootiib@hot.ee>: Mar 27 06:20PM -0700 On Friday, 27 March 2020 23:08:32 UTC+2, James Kuyper wrote: > (n4659.pdf 10.1.5p5) > Given the above declarations, what would you prefer for > noexcept(f(true)) to return? false |
David Brown <david.brown@hesbynett.no>: Mar 28 04:44PM +0100 On 27/03/2020 19:52, Öö Tiib wrote: >> low-level and embedded work exceptions are disabled.) > So the constant expression foo(42) can throw since it is somehow > evaluated run-time? May be ... I don't know how. That's not what I said. I said that "foo()" might be evaluated at run-time. Perhaps foo(43) would throw - and then "foo(43)" is not a constant expression. My understanding is that "noexcept(..)" should not evaluate its operand (like sizeof() and other such operators). It merely requires the type of the parameters, and their values don't matter. So if "foo(43)" might throw, then as far as noexcept() is concerned, "foo(x)" could throw regardless of which "x" you use. Having said that, it surprises me a little that the compiler can't use its knowledge of foo (whose definition must be visible) to see that "foo(x)" never throws for any x, and thus consider it as though it were marked "noexcept" if it knows there are no exceptions ever thrown. My guess for this is one of complexity and consistency. In general, it would be impossible for a compiler to be see that a non-throwing function really cannot throw - it would be solving the halting problem. In practice, it would be easy to see for some functions and hard for other functions. This would mean that some compilers would be able to see that a function is non-throwing, while others would not do enough analysis and thus treat it as "might throw". This would be a very unpleasant inconsistency. The only clear, consistent and understandable rule would be to say that constexpr functions are like other functions - they must be considered as potentially throwing unless explicitly marked nonexcept by the programmer. (This is based on my understanding and reasoning, rather than the standards - frankly, I haven't managed to get my head around the standards here as yet.) > Reasons why > exceptions are often disabled in embedded world are unrelated and > even the situation of these being disabled is actually non-conforming. That is correct. I mentioned it merely to show the silliness of your idea that the committee members are deliberately sabotaging embedded and low-level programming in C++. > If you can write with straight face that compile time evaluated expression > may throw is normal then also you will write with same straight face that > my code is garbage. So lets better drop that. Currently, I don't think I would consider your code (that requires volatile usage that will be deprecated in C++20) to be garbage. I consider it imaginary. (I believe that this is due to your misunderstandings about what the changes to volatile in C++20 mean, not because I think you are being deliberately awkward.) |
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 28 01:22PM -0400 On 3/28/20 11:44 AM, David Brown wrote: > On 27/03/2020 19:52, Öö Tiib wrote: ... > (This is based on my understanding and reasoning, rather than the > standards - frankly, I haven't managed to get my head around the > standards here as yet.) "The predicate indicating whether a function cannot exit via an exception is called the exception specification of the function. If the predicate is false, the function has a potentially-throwing exception specification, otherwise it has a non-throwing exception specification. The exception specification is either defined implicitly, or defined explicitly by using a noexcept-specifier as a suffix of a function declarator (11.3.5). noexcept-specifier: noexcept ( constant-expression ) noexcept throw ( )" (18.4p1). Note that the phrases "exception specification", "potentially-throwing exception specification" and "non-throwing exception specification" are all italicized, an ISO convention indicating that this clause constitutes the official definition of those terms. Therefore, the value of a noexcept() expression is determined entirely by the exception specification of the function. The body of the function plays no role in determining that value, not even if it's declared inline in the same translation unit. ... > consider it imaginary. (I believe that this is due to your > misunderstandings about what the changes to volatile in C++20 mean, not > because I think you are being deliberately awkward.) That's why we both keep asking him to provide examples - so we can say to him "such code will not be deprecated in C++2020". |
"Öö Tiib" <ootiib@hot.ee>: Mar 28 10:42AM -0700 On Saturday, 28 March 2020 17:45:09 UTC+2, David Brown wrote: > see that a function is non-throwing, while others would not do enough > analysis and thus treat it as "might throw". This would be a very > unpleasant inconsistency. I already did cite relevant parts of C++14 where it was required and C++17 where it was removed. These were 8 words "unless the call is a constant expression". So if foo(43) is not constant expression but foo(42) is then noexcept(foo(43)) should be false and noexcept(foo(42)) true. I do not see what about it was inconsistent. I see how it was great. I could compile time decide between calling non-constexpr algorithms (library functions, compiler intrinsics, inline assembler or some function that did cache something) and some potentially less efficient runtime but constexpr algorithms in C++14. And I am 100% sure that all compilers do that constant expression analysis just telling the results to programmer were suddenly forbidden by C++17. > constexpr functions are like other functions - they must be considered > as potentially throwing unless explicitly marked nonexcept by the > programmer. Your immediate reaction was different: "But how could a constant expression be potentially throwing?". Now you are advocating that it is most consistent for it to be potentially throwing. > That is correct. I mentioned it merely to show the silliness of your > idea that the committee members are deliberately sabotaging embedded and > low-level programming in C++. Not only embedded programming on case of constexpr. Whole tool of detecting constant expressions in whatever context was taken away. Programmer has to make that analysis manually. I did show that it was made even in C++11 and C++14 (that had the requirement) modes of compilers. So fine, I am just stupid and silly when I complain that our tools were clearly and deliberately damaged. Damaged with unprecedented retroactive effect in C++11 and C++14 modes as well. > consider it imaginary. (I believe that this is due to your > misunderstandings about what the changes to volatile in C++20 mean, not > because I think you are being deliberately awkward.) The change deprecates volatile qualified member functions and so possibility to detect volatile this with overload resolution. You have technically already rejected usefulness of it with your praise of changes and don't see value in it. I am convinced in it because you do not see value in tool of detecting constexpr with explicit code but instead call it inconsistent. Yes, constant expressions weren't made detectable with some std::is_constexpr(foo(42)) but it wasn't needed as there was possible to write it using noexcept. On any case both possibilities that I am just stupid and silly in wanting my code to work or that there is sabotage of my tools make me equally unhappy. |
David Brown <david.brown@hesbynett.no>: Mar 28 08:35PM +0100 On 28/03/2020 18:42, Öö Tiib wrote: > So fine, I am just stupid and silly when I complain that our tools were > clearly and deliberately damaged. Damaged with unprecedented retroactive > effect in C++11 and C++14 modes as well. noexcept() has never been about "detecting constant expressions"! Until C++20, there was no way of detecting constant expressions. Now there is "is_constant_evaluated", constinit and consteval. To my mind, C++20 has significantly improved the scope for constant expressions and compile-time programming. > possibility to detect volatile this with overload resolution. > You have technically already rejected usefulness of it with your > praise of changes and don't see value in it. I have asked you repeatedly to show an example that /you/ think is good code design, and which relies on a feature of volatile that is (or which you think is) deprecated in C++20. I have not asked you to show code you think /I/ will like - that would be entirely unreasonable. > constant expressions weren't made detectable with some > std::is_constexpr(foo(42)) but it wasn't needed as there was possible > to write it using noexcept. You are conflating three completely separate concepts here. noexcept() has nothing to do with detecting constant expressions. And neither of these is remotely connected with volatile or the changes to volatile in C++20. I am still unsure as to whether you have misunderstood something in C++20 (or perhaps in an earlier version), or if you have a point which you are failing to demonstrate. Until we get an example, no one can tell. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 28 03:38PM -0400 On 3/28/20 1:42 PM, Öö Tiib wrote: > On Saturday, 28 March 2020 17:45:09 UTC+2, David Brown wrote: ... >> misunderstandings about what the changes to volatile in C++20 mean, not >> because I think you are being deliberately awkward.) > The change deprecates volatile qualified member functions and so P1152R0 mentions deprecating volatile-qualified member functions. The notes concerning the changes between r0 and r1 list the results of votes on several different issues involving volatile-qualified member functions, all but one of which was approved. However, in r4, I can find no other mention of deprecating them. Can you point me to the clause (in P1152R4) where that occurs? |
"Öö Tiib" <ootiib@hot.ee>: Mar 28 12:42PM -0700 On Saturday, 28 March 2020 21:35:23 UTC+2, David Brown wrote: > noexcept() has never been about "detecting constant expressions"! I already did cite relevant parts of C++14 where it was required and C++17 where it was removed. These were 8 words "unless the call is a constant expression". So if foo(43) is not constant expression but foo(42) is then noexcept(foo(43)) should be false and noexcept(foo(42)) true. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 28 03:54PM -0400 On 3/28/20 3:42 PM, Öö Tiib wrote: > constant expression". So if foo(43) is not constant expression but > foo(42) is then noexcept(foo(43)) should be false and noexcept(foo(42)) > true. A call to a constexpr function whose definition has been provided, has defined behavior, and which meets the requirements for a constexpr function (10.1.5) doesn't match any of the items in the list under 8.20p2 - as such, it can never fail to qualify as a constant expression, regardless of which value is passed to the function. |
"Öö Tiib" <ootiib@hot.ee>: Mar 28 01:16PM -0700 On Saturday, 28 March 2020 21:35:23 UTC+2, David Brown wrote: > there is "is_constant_evaluated", constinit and consteval. To my mind, > C++20 has significantly improved the scope for constant expressions and > compile-time programming. It does not work and so you are under some kind of illusion from worm-tongue-wording of standard. #include <iostream> #include <type_traits> constexpr int foo(int x) { if (std::is_constant_evaluated()) return x; return 666; } int main() { std::cout << (foo(42) == 42 ? "constant expressions can be detected\n" : "constant expressions can't be " "detected\n"); } Demo: <http://coliru.stacked-crooked.com/a/61f3d3e62656525e> |
"Öö Tiib" <ootiib@hot.ee>: Mar 28 02:12PM -0700 On Saturday, 28 March 2020 21:54:54 UTC+2, James Kuyper wrote: > function (10.1.5) doesn't match any of the items in the list under > 8.20p2 - as such, it can never fail to qualify as a constant expression, > regardless of which value is passed to the function. Is it removed that when conditional expression evaluates into throw expression then it is not constant expression? |
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 28 06:25PM -0400 On 3/28/20 5:12 PM, Öö Tiib wrote: >> regardless of which value is passed to the function. > Is it removed that when conditional expression evaluates into throw > expression then it is not constant expression? In n3337.pdf dated 2012-01-16, section 5.19p2 includes "an invocation of a constexpr function with arguments that, when substituted by function invocation substitution (7.1.5), do not produce a constant expression;" as one of the things that fails to qualify as a constant expression. n3797.pdf, dated 2013-10-13, drops that item from the list. So it would appear that the change you're complaining about took place about 7-8 years ago. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Mar 28 04:11PM -0700 > n3797.pdf, dated 2013-10-13, drops that item from the list. > So it would appear that the change you're complaining about took place > about 7-8 years ago. Drafts of the C++ standard are available in this git repo: https://github.com/cplusplus/draft The commit that removed that wording is: commit 7cb8947bec0eaf7788e75e3b36e23f4714e157a8 Author: Richard Smith <richard@metafoo.co.uk> Date: 2012-05-05 19:59:36 -0700 N3652 Relaxing constraints on constexpr functions Conflicts resolved as indicated by N3652. N3652 is here: https://isocpp.org/files/papers/N3652.html Relaxing constraints on constexpr functions constexpr member functions and implicit const This paper describes the subset of N3597 selected for inclusion in C++14, relaxing a number of restrictions on constexpr functions. These changes all received overwhelmingly strong or unopposed support under review of the Evolution Working Group. It also incorporates Option 2 of N3598. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
red floyd <no.spam@its.invalid>: Mar 28 11:04AM -0700 I was looking for a way to use standard algorithms with a range of integers. For example, for the range [1, N), where N can be arbitrarily large. The problem to me appears to be that library algorithms only work on iterators. I didn't want to just create a collection containing the integers, because I was playing with some math which might use large values (on the order of over a million), and I didn't want to waste the space. So for my purposes, I came up with the following. [BEGIN CODE] namespace my { template<typename Integral, typename UnaryFunction> Integral for_each(Integral first, Integral last, UnaryFunction func) { while (first < last) { func(first); ++first; } return first; } template<typename Integral, typename UnaryFunction> Integral for_each(Integral first, Integral last, Integral interval, UnaryFunction func) { while (first < last) { func(first); first += interval; } return first; } } [END CODE] I don't want to duplicate something already written, is there something similar in the Standard Library? -- red floyd |
Sam <sam@email-scan.com>: Mar 28 02:43PM -0400 red floyd writes: > the integers, because I was playing with some math which might use large > values (on the order of over a million), and I didn't want to waste the > space. It is trivial to whip up an iterator that will iterate over a sequence of a billion values, that will require zero bytes of memory. The size of the sequence covered by an iterator has no direct relation to the amount of memory required for it. There are iterators that iterate over something that's not represented by a memory range. People's Exhibit "A": you might be familiar with std::istreambuf_iterator? It will happily iterate over each byte of a terabyte-sized file, without needing a terabyte of RAM. You need to divorce yourself from the notion that just because you have an iterator that produces a million ints, these million int must be in RAM, somewhere. > [END CODE] > I don't want to duplicate something already written, is there > something similar in the Standard Library? Well, you can use std::for_each, with a custom iterator whose operator* return *this, perhaps. Or, maybe std::fill or std::generate can be put to good use here, with a few custom classes. |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 28 08:30PM +0100 You could use an iterator which wraps a normal iterator and includes a gap-value. Something like this (don't know if everything is correct): #include <iterator> template<typename RandIt> struct gap_iterator { using value_type = typename std::iterator_traits<RandIt>::value_type; gap_iterator() = default; gap_iterator( RandIt it, std::size_t gap ); gap_iterator( gap_iterator const &other ); gap_iterator &operator =( gap_iterator const &rhs ); bool operator !=( gap_iterator const &other ); value_type &operator *(); value_type *operator ->(); gap_iterator &operator ++(); gap_iterator &operator +=( std::size_t offset ); private: RandIt m_it; size_t m_gap; }; template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( RandIt it, std::size_t gap ) { m_it = it; m_gap = gap; } template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( gap_iterator const &other ) { m_it = other.m_it; m_gap = other.m_gap; } template<typename RandIt> inline typename gap_iterator<RandIt>::gap_iterator &gap_iterator<RandIt>::operator =( gap_iterator const &rhs ) { m_it = rhs.m_it; m_gap = rhs.m_gap; return *this; } template<typename RandIt> inline bool gap_iterator<RandIt>::operator !=( gap_iterator const &rhs ) { return m_it != rhs.m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type &gap_iterator<RandIt>::operator *() { return *m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type *gap_iterator<RandIt>::operator ->() { return &*m_it; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator ++() { m_it += m_gap; return *this; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator +=( std::size_t offset ) { m_it += offset * m_gap; return *this; } #include <iostream> #include <algorithm> #include <cstdlib> using namespace std; int main() { int ai[16 * 16]; gap_iterator<int *> giiBegin( ai, 16 ), giiEnd( giiBegin ); giiEnd += 16; for_each( giiBegin, giiEnd, []( int &v ) { v = rand(); } ); for_each( giiBegin, giiEnd, []( int v ) { cout << v << " "; } ); } |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 28 08:46PM +0100 Why does this changed version not work ? #include <iterator> template<typename RandIt> struct gap_iterator { using value_type = typename std::iterator_traits<RandIt>::value_type; gap_iterator() = default; gap_iterator( RandIt it, std::size_t gap ); gap_iterator( gap_iterator const &other ); gap_iterator &operator =( gap_iterator const &rhs ); bool operator !=( gap_iterator const &other ); value_type &operator *(); value_type *operator ->(); gap_iterator &operator ++(); gap_iterator &operator +=( std::size_t offset ); friend gap_iterator operator +( gap_iterator const &gi, std::size_t offset ); private: RandIt m_it; size_t m_gap; }; template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( RandIt it, std::size_t gap ) { m_it = it; m_gap = gap; } template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( gap_iterator const &other ) { m_it = other.m_it; m_gap = other.m_gap; } template<typename RandIt> inline typename gap_iterator<RandIt>::gap_iterator &gap_iterator<RandIt>::operator =( gap_iterator const &rhs ) { m_it = rhs.m_it; m_gap = rhs.m_gap; return *this; } template<typename RandIt> inline bool gap_iterator<RandIt>::operator !=( gap_iterator const &rhs ) { return m_it != rhs.m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type &gap_iterator<RandIt>::operator *() { return *m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type *gap_iterator<RandIt>::operator ->() { return &*m_it; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator ++() { m_it += m_gap; return *this; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator +=( std::size_t offset ) { m_it += offset * m_gap; return *this; } template<typename RandIt> inline gap_iterator<RandIt> operator +( gap_iterator<RandIt> const &gi, std::size_t offset ) { gap_iterator<RandIt> ret( gi ); gi.m_it += offset * gi.m_gap; return ret; } #include <iostream> #include <algorithm> #include <cstdlib> using namespace std; int main() { int ai[16 * 16]; gap_iterator<int *> giiBegin( ai, 16 ), giiEnd( giiBegin + 16 ); //giiEnd += 16; for_each( giiBegin, giiEnd, []( int &v ) { v = rand(); } ); for_each( giiBegin, giiEnd, []( int v ) { cout << v << " "; } ); } |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 28 08:47PM +0100 > gi.m_it += offset * gi.m_gap; ret.m_it += offset * ret.m_gap; |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 28 08:49PM +0100 Am 28.03.2020 um 20:47 schrieb Bonita Montero: >> gi.m_it += offset * gi.m_gap; > ret.m_it += offset * ret.m_gap; ret.m_it = ret.m_it + offset * ret.m_gap; The contained iterator might not know +=. |
Bonita Montero <Bonita.Montero@gmail.com>: Mar 28 08:58PM +0100 Got it: #include <iterator> template<typename RandIt> struct gap_iterator { using value_type = typename std::iterator_traits<RandIt>::value_type; gap_iterator() = default; gap_iterator( RandIt it, std::size_t gap ); gap_iterator( gap_iterator const &other ); gap_iterator &operator =( gap_iterator const &rhs ); bool operator !=( gap_iterator const &other ); value_type &operator *(); value_type *operator ->(); gap_iterator &operator ++(); gap_iterator &operator +=( std::size_t offset ); template<typename RandIt> friend gap_iterator<RandIt> operator +( gap_iterator<RandIt> const &gi, std::size_t offset ); private: RandIt m_it; size_t m_gap; }; template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( RandIt it, std::size_t gap ) { m_it = it; m_gap = gap; } template<typename RandIt> inline gap_iterator<RandIt>::gap_iterator( gap_iterator const &other ) { m_it = other.m_it; m_gap = other.m_gap; } template<typename RandIt> inline typename gap_iterator<RandIt>::gap_iterator &gap_iterator<RandIt>::operator =( gap_iterator const &rhs ) { m_it = rhs.m_it; m_gap = rhs.m_gap; return *this; } template<typename RandIt> inline bool gap_iterator<RandIt>::operator !=( gap_iterator const &rhs ) { return m_it != rhs.m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type &gap_iterator<RandIt>::operator *() { return *m_it; } template<typename RandIt> inline typename gap_iterator<RandIt>::value_type *gap_iterator<RandIt>::operator ->() { return &*m_it; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator ++() { m_it += m_gap; return *this; } template<typename RandIt> inline gap_iterator<RandIt> &gap_iterator<RandIt>::operator +=( std::size_t offset ) { m_it += offset * m_gap; return *this; } template<typename RandIt> inline gap_iterator<RandIt> operator +( gap_iterator<RandIt> const &gi, std::size_t offset ) { gap_iterator<RandIt> ret( gi ); ret.m_it = ret.m_it + offset * ret.m_gap; return ret; } #include <iostream> #include <algorithm> #include <cstdlib> using namespace std; int main() { int ai[16 * 16]; gap_iterator<int *> giiBegin( ai, 16 ), giiEnd( giiBegin + 16 ); //giiEnd += 16; for_each( giiBegin, giiEnd, []( int &v ) { v = rand(); } ); for_each( giiBegin, giiEnd, []( int v ) { cout << v << " "; } ); } |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Mar 28 08:51PM On Sat, 2020-03-28, red floyd wrote: > integers. For example, for the range [1, N), where N can be arbitrarily > large. The problem to me appears to be that library algorithms only > work on iterators. Seems to me the real problem is you don't have iterators over [1, N). Isn't there such a thing in Boost or something? If not, I imagine it would be easy to write something so that: const Range<int> r{1, 4711}; std::for_each(r.begin(), r.end(), f); /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
xyz91987@gmail.com: Mar 28 07:47PM Protect yourself and your loved ones ! KILL the coronavirus right now ! And save LOTS OF CASH New tested, scientificly proven and amazing antivirus against coronavirus using Chloroquine and Colchicine at very low price (33% discount) Satisfaction garanteed or your money back ! http://als0p.atwebpages.com/coronavirus/coronavirus-en.php Protégez-vous et vos proches! TUEZ le coronavirus dès maintenant! Et économisez BEAUCOUP D'ARGENT Nouvel antivirus testé, scientifiquement prouvé et étonnant contre le coronavirus utilisant la Chloroquine et la Colchicine à très bas prix (33% de réduction) Satisfaction garantie ou agrent remie ! http://als0p.atwebpages.com/coronavirus/coronavirus-fr.php |
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