Friday, March 30, 2018

Digest for comp.lang.c++@googlegroups.com - 7 updates in 5 topics

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 30 08:49AM +0200

On 29.03.2018 18:18, Latimerius wrote:
 
> It's not compilable as the constructor call in main() is apparently ambiguous. Two things that I don't understand about this:
 
> 1) why does the second C's ctor even apply? Shouldn't the corresponding std::tuple ctor be explicit?
> 2) assuming both C's ctors are applicable - shouldn't the first one be a better match? I guess it only requires a single conversion (from lambda to C:::Fn) whereas the second one requires two (lambda to C::Fn as before and then from C::Fn to std::tuple).
 
Both `tuple` and `function` have templated constructors that can take
just about any argument.
 
One way to disambiguate is to use a templated constructor that checks
the kind of argument (e.g. via a traits class like below) and forwards
to a constructor with explicit mention of the kind of argument:
 
 
#include <functional>
#include <tuple>
#include <iostream>
#include <type_traits>
 
namespace arg {
struct Some_type {};
struct Tuple {};
};
 
namespace c_arg {
template< class Arg > struct Kind_ { using T = arg::Some_type; };
template< class F > struct Kind_<std::tuple<F>> { using T =
arg::Tuple; };
 
template< class F > using Kind = typename Kind_<F>::T;
}
 
struct C {
using Fn = std::function <void (int )>;
Fn mFn;
 
C( arg::Some_type, Fn fn )
: mFn{ std::move( fn ) }
{ mFn( 1 ); }
 
C( arg::Tuple, std::tuple <Fn> t )
: mFn{ std::move( std::get<0>( t )) }
{ mFn( 2 ); }
 
template< class Arg >
C( Arg&& arg )
: C{ c_arg::Kind<std::remove_reference_t<Arg>>{},
std::forward<Arg>( arg ) }
{}
};
 
auto main()
-> int
{
auto lambda = [](int i) { std::cout << i << std::endl; };
std::tuple<std::function<void(int)>> t{ lambda };
 
C c1{ lambda };
C c2( t );
}
 
 
In practice this technique is used to disambiguate
 
* rvalue reference versus reference to const, for templated type,
* raw array versus pointer, for templated type.
 
Cheers & hth.,
 
- Alf
Latimerius <l4t1m3r1us@gmail.com>: Mar 30 01:32PM -0700

Thanks for the advice on how to disambiguate - this is going to be useful. Could you also help me understand why the constructor call is ambiguous in the first place? Apparently I need to fix my understanding of overload resolution.
 
My current understanding leads me to believe that the tuple-taking constructor should require one more argument conversion and thus be a worse candidate. However, both g++ and clang++ disagree...
Tim Rentsch <txr@alumni.caltech.edu>: Mar 29 11:49PM -0700


> I suppose cbor::value (msgpack::value) would be an option, but value by
> itself seems uninspired. Or perhaps cbor::packed (msgpack::packed), as
> these encapsulate packed arrays of bytes.
 
I've kept all the context so as not to have to decide what to cut.
 
I think 'cbor' is a good choice for the name of the namespace (in
case it needs saying, given the context with parallel namespaces
such as msgpack, etc).
 
I think 'value' is a poor choice for a class name. It doesn't
say anything, kind of like 'cbor::thing'. The name 'packed' is
at least more descriptive than 'value', but still IMO a poor
choice.
 
If I were charged with proposing a name (and following the rule
of no uppercase letters), I think my first suggestion would be
'encoded_item'. (Needless to say that assumes that an instance
of the class does indeed hold an encoded item.) My rationale
is this name leaves no doubt in the reader's mind what an
instance of this class represents. It doesn't require any
guessing, imagination, or outside context, to undrstand what
is meant.
 
Does that all make sense?
Daniel <danielaparker@gmail.com>: Mar 30 10:40AM -0700

On Friday, March 30, 2018 at 2:50:07 AM UTC-4, Tim Rentsch wrote:
> guessing, imagination, or outside context, to undrstand what
> is meant.
 
> Does that all make sense?
 
Thanks for your comments and suggestions. I think all the comments agreed
that the namespace name should be cbor (singular).
 
For class name, 'encoded_item' could work, but I'm also inclined to a little
repetition as suggested in Richard's post and include "cbor" in the class
name. I agree with your comments about value as a class name.
 
I tentatively went with boost's approach for tuple, iterator, and bimap
(subdirectory singular, namespace plural, class name singular), hence cbor
(subdirectory), cbors (namespace) and cbor (class name). But I'm not
enthusiastic about it (partly from reflecting on comments on this thread)
and am thinking of changing it to cbor, cbor, and packed_cbor.
 
Daniel
Tim Rentsch <txr@alumni.caltech.edu>: Mar 29 11:27PM -0700


> I know better than to engage with a known troll, but....
 
but... some days you just have poor impulse control?
 
(just a friendly rib - I must plead guilty to the same
offense :)
Tim Rentsch <txr@alumni.caltech.edu>: Mar 29 11:23PM -0700


> So in the end, if everyone had been writing mostly ~50 line routines,
> I don't think the lack of structure within those routines would have
> attracted too much attention.
 
I pretty much agree with all of the above. I might emphasize
that it is the drive for understandable programs that leads to
small routines, and not that a drive for small routines will
necessarily lead to understandable programs. (And which I
believe is one of the points you were making, or at least would
agree with.)
 
> arbitrary set of rules. I'm good with whatever makes a program
> clearer. On occasion, that involves a goto. We know you *can* always
> do without, but sometimes the cure is worse than the disease.
 
Yes. Even Dijkstra said he wasn't dogmatic about avoiding goto.
My point though is about size. Routines of 50 lines can be
manageable, and certainly they are more likely to be manageable
than routines of 100 or 200 lines. Still, 50 line routines should
be rare rather than typical. Average function length normally
should be under 20 lines, and median length closer to 10. A
length of 50 lines should normally be 95th percentile or better -
anything worse is a strong indication that some refactoring is
needed. Like what you said, I don't mean to make an arbitrary
rule, but to give a useful empirical guideline for after-the-fact
assessment.
 
>> and hope you will explain.)
 
> My experience is that those usages are pretty much interchangeable in
> the field. Although I'd agree that in linguistic terms they're not.
 
I agree that misusage is common, but still deserves being called
out. There are two problems. The first is that different people
use the term in different ways - does it mean usual, widespread,
normal, typical, common, well-understood, generally accepted, or
some combination of those, or perhaps something else entirely?
There are arguments over whether some construction is or is not
"idiomatic". Or, another example, someone asking for "/the/
idiomatic way" (my emphasis) to write a particular program. There
is never a single good way to write a program (and yes sometimes
"idiomatic" is used as though it were synonymous with "good").
Being precise is an important habit in software development;
continuing the definitely imprecise use of "idiomatic" is
cultivating a bad habit.
 
The second problem is more subtle. The word "idiomatic" sounds,
by virtue of its length and narrow application, like a high-brow
word. Characterizing a pattern as "idiomatic" lends an air of
legitimacy that often is not deserved. At some level this kind of
usage is intellectually dishonest (even if not always consciously
or deliberately): it sounds objective, but as often as not boils
down to nothing more than "a pattern I think is good". That kind
of rhetorical trick is best left to the domain of politicians
(where for better or worse it appears to be inescapable).
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Mar 29 09:30PM -0700

On 3/27/2018 8:55 PM, Chris M. Thomasson wrote:
> function.
 
> Here is my C++11 code [1]:
 
> https://pastebin.com/raw/KAt4nhCj
[...]
 
> Thanks.
 
> [1] code:
> ___________________________
[...]
> ___________________________
 
Perhaps I can explain this through a series of questions. Let me try to
start...
 
Question 1
 
How many people want to iterate over a shared data-structure without
using a read/write mutex? In other words, would making the writers run
concurrently with the readers be beneficial to you at all? Readers can
run full steam ahead, while the writers do not interrupt them. This can,
increase concurrency and overall performance, and can get rid of certain
bottlenecks especially if the problem is mostly read based.
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: