Sunday, March 29, 2020

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

red floyd <no.spam@its.invalid>: Mar 28 07:01PM -0700

On 3/28/20 1:51 PM, Jorgen Grahn wrote:
>> 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).
 
TBH, I'm surprised the Committee hasn't addressed this.
Ned Latham <nedlatham@woden.valhalla.oz>: Mar 28 09:14PM -0500

red floyd wrote:
> > > work on iterators.
 
> > Seems to me the real problem is you don't have iterators over [1, N).
 
> TBH, I'm surprised the Committee hasn't addressed this.
 
Can you construct a dummy object for the iterator's sake?
danielaparker@gmail.com: Mar 28 08:44PM -0700

On Saturday, March 28, 2020 at 2:04:11 PM UTC-4, red floyd wrote:
> I was looking for a way to use standard algorithms with a range of
> integers.
 
Option 1:
 
#include <iterator>
#include <algorithm>
 
template <class Iterator,class Enable = void>
class integer_iterator
{
};
 
template <class T>
class integer_iterator<T,typename std::enable_if<std::is_integral<T>::value
>::type>
{
T value_;
T step_;
public:
using iterator_category = std::random_access_iterator_tag;
 
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = typename std::conditional<std::is_const<T>::value,
value_type*,
const value_type*>::type;
using reference = typename std::conditional<std::is_const<T>::value,
value_type&,
const value_type&>::type;
 
public:
explicit integer_iterator(T n = 0, T step = 1) : value_(n), step_(step)
{
}
 
integer_iterator(const integer_iterator&) = default;
integer_iterator(integer_iterator&&) = default;
integer_iterator& operator=(const integer_iterator&) = default;
integer_iterator& operator=(integer_iterator&&) = default;
 
template <class U,
class=typename std::enable_if<!std::is_same<U,T>::value &&
std::is_convertible<U,T>::value>::type>
integer_iterator(const integer_iterator<U>& other)
: value_(other.value_)
{
}
 
reference operator*() const
{
return value_;
}
 
T operator->() const
{
return &value_;
}
 
integer_iterator& operator++()
{
value_ += step_;
return *this;
}
 
integer_iterator operator++(int)
{
integer_iterator temp = *this;
++*this;
return temp;
}
 
integer_iterator& operator--()
{
value_ -= step_;
return *this;
}
 
integer_iterator operator--(int)
{
integer_iterator temp = *this;
--*this;
return temp;
}
 
integer_iterator& operator+=(const difference_type offset)
{
value_ += offset;
return *this;
}
 
integer_iterator operator+(const difference_type offset) const
{
integer_iterator temp = *this;
return temp += offset;
}
 
integer_iterator& operator-=(const difference_type offset)
{
return *this += -offset;
}
 
integer_iterator operator-(const difference_type offset) const
{
integer_iterator temp = *this;
return temp -= offset;
}
 
difference_type operator-(const integer_iterator& rhs) const
{
return value_ - rhs.value_;
}
 
reference operator[](const difference_type offset) const
{
return *(*this + offset);
}
 
bool operator==(const integer_iterator& rhs) const
{
return value_ == rhs.value_;
}
 
bool operator!=(const integer_iterator& rhs) const
{
return !(*this == rhs);
}
 
bool operator<(const integer_iterator& rhs) const
{
return value_ < rhs.value_;
}
 
bool operator>(const integer_iterator& rhs) const
{
return rhs < *this;
}
 
bool operator<=(const integer_iterator& rhs) const
{
return !(rhs < *this);
}
 
bool operator>=(const integer_iterator& rhs) const
{
return !(*this < rhs);
}
 
inline
friend integer_iterator<T> operator+(
difference_type offset, integer_iterator<T> next)
{
return next += offset;
}
};
 
int main(int argc, char** argv)
{
integer_iterator<int> first(1,10);
integer_iterator<int> last(100000001, 10);
 
int n = 0;
auto f = [&n](int i) {n += i;};
std::for_each(first, last, f);
}
 
Option 2
 
int main(int argc, char** argv)
{
int n = 0;
auto f = [&n](int i) {n += i;};
for (int i = 1; i < 100000001; i += 10)
{
f(i);
}
}
 
Decisions, decisions ...
 
Daniel
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
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 29 02:46PM +0200

On 28.03.2020 19:04, red floyd wrote:
> [END CODE]
 
> I don't want to duplicate something already written, is there
> something similar in the Standard Library?
 
In C++20 there will be std::something::idiota, or "iota" as the Greeks
tend to shorten it, used like
 
for( const int i: idiota( n ) ) do { //... use `i` here
 
With the
under-construction-library-that-I-really-need-to-finish-sometime you can
write similar but much more clear code like
 
for( const int i: zero_to( n ) ) { //... Use `i` here.
 
<url:
https://github.com/alf-p-steinbach/cppx-core-language/blob/master/source/cppx-core-language/syntax/collection-util/Sequence_.hpp>.
 
This is not an `idiota` copy; the library and concept, though not this
particular implementation, predates `idiota` by many years.
 
There are good reasons for all the shenanigans in that code, so it
illustrates what you're dealing with for defining a general integers
iterator. There may still be bugs. It's not extensively tested.
 
 
- Alf
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 << " "; } );
}
"Öö Tiib" <ootiib@hot.ee>: Mar 28 05:29PM -0700

On Sunday, 29 March 2020 00:25:27 UTC+2, James Kuyper wrote:
 
> 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.
 
I am really not complaining about that since my constexpr functions
don't throw ... it is just another inconvenience. Are these now
ill-formed constant expressions instead of being non-constant
expressions?
 
I am complaining that constant expression is not detectable with code.
So I must keep track if something evaluates to constant expression or
not as monkey-coder; I can't make code that does it automatically.
 
The requirement that was useful that noexcept was required to return
true to calls that were constant expressions was removed.
Things that I do not see much use for in their current form:
std::is_constant_evaluated, constinit and consteval were added.
David Brown <david.brown@hesbynett.no>: Mar 29 10:24AM +0200

On 28/03/2020 20:42, Öö 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.
 
As I said - noexcept() has never been about detecting constant expressions.
 
I understand that you think it's odd that a constant expression can
return "false" for noexcept. But that is beside the point.
 
You claimed the change to noexcept() broke the tool for detecting
constant expressions. I was hoping for a justification for that, rather
than another side-track.
David Brown <david.brown@hesbynett.no>: Mar 29 10:31AM +0200

On 28/03/2020 21:16, Öö Tiib wrote:
>> compile-time programming.
 
> It does not work and so you are under some kind of illusion from
> worm-tongue-wording of standard.
 
I haven't read the standard here yet.
 
But I must admit I assumed that std::is_constant_evaluated() was
basically a standardisation of the useful gcc extension
__builtin_constant_p(...). Unfortunately, it is not.
 
"Öö Tiib" <ootiib@hot.ee>: Mar 29 01:47AM -0700

On Sunday, 29 March 2020 11:24:47 UTC+3, David Brown wrote:
> > foo(42) is then noexcept(foo(43)) should be false and noexcept(foo(42))
> > true.
 
> As I said - noexcept() has never been about detecting constant expressions.
 
But C++ has never been what you said but it is always been what standard
said. And C++14 said that noexcept operator should detect constant
expressions:
 
The result of the noexcept operator is false if in a
potentially-evaluated context the expression would contain
 
- a potentially-evaluated call83 to a function, member function,
function pointer, or member function pointer that does not have
a non-throwing exception-specification ([except.spec]),
unless the call is a constant expression ([expr.const]),
 
> I understand that you think it's odd that a constant expression can
> return "false" for noexcept. But that is beside the point.
 
You misrepresent. I do think it's odd that such change was made
and hastily implemented in all compilers with retroactive effect in
C++11 and C++14 modes too. Despite in C++11 and C++14 the noexcept
operator was required to detect constant expressions.
 
> You claimed the change to noexcept() broke the tool for detecting
> constant expressions. I was hoping for a justification for that, rather
> than another side-track.
 
I do not even understand what you expect. Some kind of philosophical
debate? Facts are there. I do not know justifications to those facts.
"Öö Tiib" <ootiib@hot.ee>: Mar 29 02:08AM -0700

On Sunday, 29 March 2020 11:31:29 UTC+3, David Brown wrote:
 
> But I must admit I assumed that std::is_constant_evaluated() was
> basically a standardisation of the useful gcc extension
> __builtin_constant_p(...). Unfortunately, it is not.
 
Also __builtin_constant_p does not work. Only noexcept did but stopped.
Linus Torvalds trying to figure fixes to __builtin_constant_p :
https://lkml.org/lkml/2018/3/17/184
David Brown <david.brown@hesbynett.no>: Mar 29 11:38AM +0200

On 29/03/2020 10:47, Öö Tiib wrote:
 
> But C++ has never been what you said but it is always been what standard
> said. And C++14 said that noexcept operator should detect constant
> expressions:
 
No!
 
C++14 and earlier said constant expressions were /part/ of the logic in
determining the result of the noexcept operator. That does not mean, as
you have been claiming, that noexcept is a tool for determining if
something is a constant expression.
 
> and hastily implemented in all compilers with retroactive effect in
> C++11 and C++14 modes too. Despite in C++11 and C++14 the noexcept
> operator was required to detect constant expressions.
 
I guess the prevailing opinion (of those who know about these things,
unlike me) is that the earlier behaviour was a mistake.
 
>> than another side-track.
 
> I do not even understand what you expect. Some kind of philosophical
> debate? Facts are there. I do not know justifications to those facts.
 
Neither the facts, the standards (earlier or later versions), nor what
you have now written support the idea that noexcept() was a way to
identify constant expressions, or that the changes broke such methods,
or that the changes were made maliciously, callously, or without careful
consideration.
David Brown <david.brown@hesbynett.no>: Mar 29 11:48AM +0200

On 29/03/2020 11:08, Öö Tiib wrote:
 
> Also __builtin_constant_p does not work. Only noexcept did but stopped.
> Linus Torvalds trying to figure fixes to __builtin_constant_p :
> https://lkml.org/lkml/2018/3/17/184
 
What do you mean, "__builtin_constant_p does not work" ? It works
perfectly well, and I have used it - as have many people. It might not
do what you think in all cases, such as the one Torvalds is describing -
but see the follow-ups for an explanation of that.
 
Perhaps what you mean is "It does not work for my particular case, while
an abuse of noexcept() happened to work. But I won't tell anyone the
details."
"Öö Tiib" <ootiib@hot.ee>: Mar 29 03:27AM -0700

On Sunday, 29 March 2020 12:39:01 UTC+3, David Brown wrote:
> determining the result of the noexcept operator. That does not mean, as
> you have been claiming, that noexcept is a tool for determining if
> something is a constant expression.
 
It was the only thing in standard that had requirement of detecting
if something is constant expression, makeing nothing ill-formed doing
so and returning constant expression itself. Nothing else (including
non-standard __builtin_constant_p) had those properties.
So it was useful as such tool but now it isn't.
 
> > operator was required to detect constant expressions.
 
> I guess the prevailing opinion (of those who know about these things,
> unlike me) is that the earlier behaviour was a mistake.
 
It is void argument to me. I have just my work to do and I
want to do it well. You post zero code how I should do it now,
just popular votes and alleged opinions of your "authorities".
 
> identify constant expressions, or that the changes broke such methods,
> or that the changes were made maliciously, callously, or without careful
> consideration.
 
I would probably be "fixed" too by now if I had direct evidence about
malice. Forces that can enforce retroactive "fixes" in all compilers
have enough resources to "fix" people too. But mine is just opinion
based on facts there are.
"Öö Tiib" <ootiib@hot.ee>: Mar 29 03:33AM -0700

On Sunday, 29 March 2020 12:48:51 UTC+3, David Brown wrote:
 
> Perhaps what you mean is "It does not work for my particular case, while
> an abuse of noexcept() happened to work. But I won't tell anyone the
> details."
 
You unlike me are posting zero code, quotes and/or cites. So I feel your
posture that I am withholding details insulting.
David Brown <david.brown@hesbynett.no>: Mar 29 01:56PM +0200

On 29/03/2020 12:33, Öö Tiib wrote:
>> details."
 
> You unlike me are posting zero code, quotes and/or cites. So I feel your
> posture that I am withholding details insulting.
 
I am not posting code, because I don't have a problem with any code.
This whole discussion started with /your/ claim that C++20 breaks
volatile and makes it impossible to write low-level code that uses it.
What would you like me to post - code that has a volatile variable and
writes to it?
 
#define output_register *((volatile uint32_t *) 0x1234)
 
void set_output(uint32_t x) {
output_register = x;
}
 
That works fine in every C and C++ standard.
 
I don't have any sample code with noexcept, because I disable exceptions
in my embedded C++ code. (Yes, I know that is a non-conforming
extension in my compiler.)
 
 
/You/ are the one with complaints about the standards and how changes
break your code. /You/ are the one that said C++20 changes volatile and
breaks your code - the onus is on /you/ to post code that shows this
effect. /You/ are the one that said C++17 changes noexcept and breaks
your code (though I still haven't a clue how that relates to your
complain about "volatile").
 
I can't give any code snippets or references to problems with volatile
or noexcept, because I don't have any problems. I can't give any code
snippets or references regarding /your/ problems with volatile and
noexcept, because you won't say what they are or show examples. You
have given some references, but no indication as to why they are relevant.
 
 
If you want to warn people about standards changes that break real,
useful code, then post some examples so that we can learn.
 
If you want to get help making your code robust in the face of changes,
post some samples so that we can help. (I am not guaranteeing help, and
I am sure others would be more helpful than I could be - but at least
people can try.)
 
If you want to complain about the changes causing you trouble, post some
examples so that we can see the problem and sympathise, and possibly
make useful guesses as to the reason behind the changes. We all know
the C++ committee and compiler writers are mere humans and make mistakes.
 
If you want to convince people that you have misunderstood the changes,
or that you have been writing weird code that merely happens to work by
luck, then continue posting red-herrings, mixing up topics, claiming
malice and incompetence on the part of the committees and compiler
writers, and failing to answer direct questions or show samples. If
that's the way you want to play it, I am done here - I can't see any way
to make progress.
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 29 05:30AM -0700

On Sunday, 29 March 2020 14:56:31 UTC+3, David Brown wrote:
 
> > You unlike me are posting zero code, quotes and/or cites. So I feel your
> > posture that I am withholding details insulting.
 
> I am not posting code, because I don't have a problem with any code.
 
So when I am posting code that stopped working for me then you reply
that it was weird trash anyway that merely worked by luck while it
was clearly mandated by C++14 standard to work. You do not post where
I supposedly misinterpreted standard nor advice how should I write
the code instead nor any explanations why it was retroactively
"fixed" in all compilers. Just insults. What "help" is that?
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?
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.
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: