Monday, June 12, 2017

Digest for comp.lang.c++@googlegroups.com - 8 updates in 4 topics

Gareth Owen <gwowen@gmail.com>: Jun 12 09:47PM +0100

> auto c = v[0];
> auto& r = v[0]
 
> c is a char; to get a reference I must explicitly say so.
 
As a rationale, I'd say
i) principle of least surprise
ii) because if a function returns a reference, then auto couldn't
be used to declare a non-reference variable, which would make it a
hell of a lot less useful. There's no syntax for "concrete type for
referred to by reference on RHS"
 
std::vector<int> a;
// ... initialize ...
auto val = a[3];
// most of the time I probably don't want val to be a reference here
val += ... ; // don't want a[3] to change.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 12 11:46PM +0200

On 12-Jun-17 10:28 PM, Vir Campestris wrote:
> Why is it that when I call a function that returns a reference, and
> assign the result to an auto, it copies the value rather than declaring
> the auto as a reference?
 
I think Gareth Owen, in his reply, gave a good/likely possibility for
the rationale, namely the principle of least surprise.
 
But re the technical, you can view `auto` as `decltype` + `std::decay`.
 
Here are `std::decay<T>` rules quoted from cppreference.com:
 
• If T names the type "array of U" or "reference to array of U", the
member typedef type is U*.
 
• Otherwise, if T is a function type F or a reference thereto, the
member typedef type is std::add_pointer<F>::type.
 
• Otherwise, the member typedef type is
std::remove_cv<std::remove_reference<T>::type>::type.
 
So, array-ness, function-ness, const-ness, volatile-ness and
reference-ness are removed.
 
 
> auto c = v[0];
> auto& r = v[0]
 
> c is a char; to get a reference I must explicitly say so.
 
My main `auto` annoyance is that instead of
 
const ptr_<auto> p = foo();
 
… I must write something like
 
const auto p = pointer_result( foo() );
 
… to explicitly indicate the expected pointer-ness of the foo() result,
or else I'd have to use the operator notation; i.e., that `auto` is by
far not as powerful as template function argument deduction. :(
 
 
Cheers!,
 
- Alf
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 13 12:20AM +0100

Thems is the rules. auto mimics template type deduction, and discards
references and const (and volatile) qualifiers. If you want the
reference or cv qualifier to be detected, use decltype(auto), which
uses decltype type deduction rules.
 
(For completeness, you were initializing not assigning. Initializing a
value type copies.)
 
Chris
 
--------------------------
On Mon, 12 Jun 2017 21:28:43 +0100
ram@zedat.fu-berlin.de (Stefan Ram): Jun 12 10:57PM

>My personal preference is to have top level `const`-s on definition
>only, because that's where they have an advantage, while in the pure
>declaration they're negative value noise.
 
I want a pure declaration (i.e., a not-defining declaration)
to be a "prototype" that can double as a part of the
documentation of the "interface" of a function.
 
The const-ness of a parameter is /not/ a part of the interface
of a function, but of it's implementation. So it belongs
into the definition, but not into a pure declaration.
 
A hypothetical language might even allow to add the const
qualifier of a parameters within the /body/ of the definition,
separating the regions of the source code into a region for
the interface and a region for the implementation:
 
int f( int x ) /* interface */
{ const x; return 2 * x; } /* implementation */
 
Of course, in the case of
 
int f( int const * const x ) ~~~
 
, the first »const« /is/ part of the interface.
Gareth Owen <gwowen@gmail.com>: Jun 12 09:59PM +0100

I had a timer class that measure the duration of its own existence.
 
In Semi-Pseudo code it looked like this.
 
typedef long long Time;
 
class Timer {
private:
Time start_time;
Time& total_time;
}
 
Timer::Timer(Time& tot) : start_time(gettimeofday()), total_time(tot)
{
}
 
Timer::~Timer()
{
end_time = gettimeofday();
total_time += end_time - start_time;
}
 
So I wanted to extend the
 
CancellableTimer : public Timer
{
private:
bool canceled;
 
public:
// if I call obj.cancel() then the destructor should
// not
void cancel(void) { canceled = true;}
}
 
Now, it seems to me that I can't get the derived class behaviour without
modifying the base class, because the base destructor always runs.
 
But it also seems that by Liskov Substitution Principle, a
CancellableTimer IS A Timer, so it'd be nice if I could extend Timer in
this way.
 
What am I missing?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 13 12:06AM +0200

On 12-Jun-17 10:59 PM, Gareth Owen wrote:
> CancellableTimer IS A Timer, so it'd be nice if I could extend Timer in
> this way.
 
> What am I missing?
 
Well, the Liskov substitution applies to instances of types, not to
types themselves. Or in other words, the LSP is about the behavior of
objects between their creation and destruction, not including what
happens before the object's constructor has finished, or after its
destructor has begun execution. For example, a derived class can conform
to the LSP wrt. a public base class, but require different constructor
arguments – that's OK, because it's not within the domain of the LSP.
 
But you are interested in what happens during destruction.
 
If a `Timer` has no behavior between the lifetime endpoints then the
solution simple: an is-a relationship is then meaningless, so don't derive.
 
I see no way to make the class derivation work without essentially
duplicating the CancellableTimer functionality up in base class Timer,
which would be meaningless except as a way to restrict the interface of
Timer.
 
Without class derivation, if you're happy with just wrapping an instance
of `Timer`, you can use dynamic or in-place allocation, and cancel it by
just not destroying the instance. For the dynamic allocation that would
leak memory, but you could preallocate say storage for 10 000 of them
and say OK, that's the implementation limit. With C++11 and later,
however, in-place allocation is not complex: there is alignment support.
 
 
Cheers & hth.,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 13 12:22AM +0200

On 13-Jun-17 12:06 AM, Alf P. Steinbach wrote:
>> end_time = gettimeofday();
>> total_time += end_time - start_time;
>> }
 
[snip]
> leak memory, but you could preallocate say storage for 10 000 of them
> and say OK, that's the implementation limit. With C++11 and later,
> however, in-place allocation is not complex: there is alignment support.
 
Sorry for that suggestion, it was dumb.
 
It applies to the general problem of preventing destructor execution,
but that's not what you need: it wouldn't even solve the problem.
 
The obvious (to you and others, but not me some little time ago)
solution is to let `CancellableTimer` just supply a different `Time`
variable to the `Timer` instance.
 
 
 
Cheers!,
 
- Alf [looking for a brick wall to bang head against]
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 13 12:13AM +0200

On 06-Jun-17 3:13 AM, Manfred wrote:
>> is a good idea anyway, but is difficult to guarantee with lots of
>> editors that still prefer other encodings.
> This is a problem only if the standard headers use non-ascii chars.
 
No, it's a general problem. Consider UTF-16. ASCII text interpreted as
UTF-16 = a lot of gobbledygook, and possibly even invalid sequences.
 
 
Cheers!, & thanks for your suggestions else-thread,
 
- Alf
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: