Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ 2017

50 views
Skip to first unread message

jacobnavia

unread,
Dec 8, 2017, 4:17:08 PM12/8/17
to
Is this really needed?

Look, constexpr if, at
https://medium.com/@LoopPerfect/c-17-vs-c-14-if-constexpr-b518982bb1e2

That piece explain us why this improvement to C++ is necessary. You have
code like this in C++ 2014.

template<unsigned n>
struct Arg {
template<class X, class…Xs>
constexpr auto operator()(X x, Xs…xs) {
return Arg<n-1>{}(xs…);
}
};

Not very readable, I agree with the author of that piece. And that is
replaced by:

template<unsigned n>
struct Get {
template<class X, class…Xs>
constexpr auto operator()(X x, Xs…xs) {
if constexpr(n > sizeof…(xs) ) {
return;
} else if constexpr(n > 0) {
return Get<n-1>{}(xs…);
} else {
return x;
}
}
};

in C++ 2017.

The use case is:

// arg<2>(0,1,2,3,4,5) == 2;

OK. You want to access the arguments of a function *by position*. Using
*names* for arguments is much better in my humble opinion, and both the
example and the solution in C++ 2017 can't escape the fact that is much
better to access arguments by their names... if any. In the case of
functions with a variable arguments list, you can (and should) use
default arguments for them, i.e. documented default args readable in the
function declaration.

What strikes me is that the only use case that the author tried to
figure out was a solution to a non-existing need: accessing your
arguments by a hard coded number.

Let's go on to the second case where the improvements should be needed.

C++ 2014:
template<class T>
auto compute(T x) -> decltype( enable_if_t< supportsAPI(T{}), int>{}) {
return x.Method();
}

You have to define the negative method that I do not show here since it
differs by a "!" only, in the condition above.

C++ 2017:
template<class T>
int compute(T x) {
if constexpr( supportsAPI(T{}) ) {
// only gets compiled if the condition is true
return x.Method();
} else {
return 0;
}
}

Yes. Obviously writing:
auto compute(T x) -> decltype( enable_if_t< supportsAPI(T{}), int>{})

is longer than

if constexpr( supportsAPI(T{}) )

Neat. Is that, however, a real need for so many programmers that the
whole language needs to be updated to support a shorter construct?

And what about C?

#if defined(API_3_5_8)

#endif

Yes but simple solutions (used everywhere) need to be updated and
rewritten in the new way...

This is what I mean with "featurism". A new feature of 2014 needs yet
another new feature in 2017 to be usable in a very terse way. And let's
go on adding features that will need more other stuff like this in 2020.

Many people will say here that the examples (the use cases) were badly
choosen. OK, but why can't the author figure out a better use case,

Why those use cases are so difficult to figure out???

Because they are very few, and even then, dangerous. Accessing arguments
by a bare index is an error in software construction, it leads to
illisible programs!

Argument NAMES should be used.

Shouldn't any new addition to C++ be justified by USE CASES???

By a survey of programmers that asked for that specific feature to be added?

If the features added are really needed by the programmers, the people
writing those descriptions wouldn't need to try to find something: it
would be obvvious to anyone that that is needed and why.

That is not the case here, so my thesis that many of these changes are
just bloat stands.

jacob

Alf P. Steinbach

unread,
Dec 8, 2017, 4:42:17 PM12/8/17
to
On 12/8/2017 10:16 PM, jacobnavia wrote:
> [snip]
>
> Argument NAMES should be used.

Consider `std::get`, for accessing items in tuples.

It's said that a programmer spends the day making tools to make tools
that will enable him to make the tools to make tools that can make the
tools to support the making of tools to make the tools to do something.

And `if constexpr` is a tool that helps make tools (like `get`) that...

* * *

In the examples you quoted I didn't understand the `decltype`, like

auto foo() -> decltype( enable_if_t<Condition, int> )

I see no need for it.

It could be that the person you quoted the example from, is very smart,
seeing something that I don't see up front; or it could be a sloppy edit
thing, that it once made sense in some other context; or, it could be
that the person is not really fluent in C++.


Cheers!,

- Alf

Richard

unread,
Dec 8, 2017, 5:30:21 PM12/8/17
to
[Please do not mail me a copy of your followup]

The poster boy use case for constexpr if is selection between algorithms
at compile-time. (It is the 3rd example on given on that web page; I
would have made it the first example.)

constexpr if is syntactic sugar that makes code easier to read,
easier to understand and easier to maintain. You could do the same
thing in C++98 because the fundamental enabling feature for compile-time
algorithm selection is the template mechanism along with specialization.

You can keep doing C++98 style compile-time algorithm selection if you
want; it worked before and will still work.

However, your code will be much easier to read, write and maintain with
constexpr if.

It is very much like lambdas. You could have written you own functor
classes before, but it was tedious and required lots of boiler plate.
This resulted in people duplicating effort of standard algorithms
because writing the functor was tedious. Lambdas give you the
syntactic sugar that makes using standard algorithms more straight
forward.

You would think that anything making C++ easier to read, write and
maintain would be welcome, but I guess some people insist on seeing
sour grapes in everything.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

jacobnavia

unread,
Dec 8, 2017, 5:32:48 PM12/8/17
to
Le 08/12/2017 à 22:42, Alf P. Steinbach a écrit :
> In the examples you quoted I didn't understand the `decltype`, like
>
>     auto foo() -> decltype( enable_if_t<Condition, int> )
>
> I see no need for it.

Well, enable_if_t returns either a type or not, depending on the
condition. If the condition is true ( supportsAPI(T{} ) it returns the
method, if not returns int, so you could have a class with optional
fields depending on some boolean construct.

Great. But why is this better than

#ifdef API_3.5_SUPPORTED

//declaration for the method

#endif

I know, that is too simple. Everyone would understand it.
Is this something many people needed?

Are the current methods of specifying that a method is not part of
another class if some API is not supported not enough that we have tyo
ponder over this kind of stuff?

How many C++ programmers would understand something with a construct like

auto foo() -> decltype( enable_if_t<Condition, int> )

How many would not understand with

#if API_3.4_SUPPORTED

#endif

It took me a lot of time just to figure what that code is MAYBE doing. I
am not at the level of asking me if there is a need for decltype, surely
not.

jacob navia

unread,
Dec 8, 2017, 6:43:59 PM12/8/17
to
Le 08/12/2017 à 22:42, Alf P. Steinbach a écrit :
What I do not understand there is this:

template<class L, class R>
auto fold(L l, R r) {
using lTag = typename L::tag;
using rTag = typename R::tag;
if constexpr( is_base_of<rTag, BarTag>::value ) {
if constexpr( is_same<lTag, FooTag>::value ) {
return foldFB(l,r);
} else {
return foldBB(l,r);
} else {
return foldFF();
}
}

Do you read like me?

if (constantexpr(etc) {
}
else {
}

And here the if is FINISHED, but the sample code goes on with

else return foldFF();

???

else what?

Has c++ changed the semnatics of the if so that there is

if this

else that

and then a THIRD else???

I think that the writer forgot to put some condition in the second
"else". Do you agree?

Because if not C++ is REALLY unreadable!


jacob navia

unread,
Dec 8, 2017, 6:46:41 PM12/8/17
to
Le 08/12/2017 à 23:29, Richard a écrit :
> The poster boy use case for constexpr if is selection between algorithms
> at compile-time. (It is the 3rd example on given on that web page; I
> would have made it the first example.)

I did not mention the third example because it is so buggy

here it is

template<class L, class R>
auto fold(L l, R r) {
using lTag = typename L::tag;
using rTag = typename R::tag;
if constexpr( is_base_of<rTag, BarTag>::value ) {
if constexpr( is_same<lTag, FooTag>::value ) {
return foldFB(l,r);
} else {
return foldBB(l,r);
} else {
return foldFF();
}
}

Note that we have

if ()

else ...

and then ANOTHER ELSE!

Either the writer forgot a condition in the second if, or C++ has become
so uynreadable that you can write this kind of stuff meaning ... meaning
what?

I do not know, An "if" constructs returns a BOOLEAN value, it is either
true or false, so the "else" cares about the false condition, but there
are NO MORE conditions...

But with C++ you really never know...

Ian Collins

unread,
Dec 8, 2017, 8:29:43 PM12/8/17
to
On 12/09/2017 12:43 PM, jacob navia wrote:
>
> What I do not understand there is this:
>
> template<class L, class R>
> auto fold(L l, R r) {
> using lTag = typename L::tag;
> using rTag = typename R::tag;
> if constexpr( is_base_of<rTag, BarTag>::value ) {
> if constexpr( is_same<lTag, FooTag>::value ) {
> return foldFB(l,r);
> } else {
> return foldBB(l,r);
> } else {
> return foldFF();
> }
> }
>
> Do you read like me?

Someone (the authour) didn't check their code! The last else probably
belongs with the first if.

--
Ian.

Alf P. Steinbach

unread,
Dec 8, 2017, 9:55:58 PM12/8/17
to
On 12/8/2017 11:32 PM, jacobnavia wrote:
> Le 08/12/2017 à 22:42, Alf P. Steinbach a écrit :
>> In the examples you quoted I didn't understand the `decltype`, like
>>
>>      auto foo() -> decltype( enable_if_t<Condition, int> )
>>
>> I see no need for it.
>
> Well, enable_if_t returns either a type or not, depending on the
> condition. If the condition is true ( supportsAPI(T{} ) it returns the
> method, if not returns int,

No no. It stands for the type `int` if the condition is true. Otherwise
it gives compilation failure, which is of a kind ignored for templates
(Substitution Failure for a template argument Is Not An Error, SFINAE).

Since it already stands directly for a type, when it compiles, the
`decltype` appears to be completely unnecessary.


Cheers!,

- ALf

David Brown

unread,
Dec 9, 2017, 12:27:07 PM12/9/17
to
It looks to me to be a simple typo, and should be:

if constexpr( is_base_of<rTag, BarTag>::value ) {
if constexpr( is_same<lTag, FooTag>::value ) {
return foldFB(l,r);
} else {
return foldBB(l,r);
}
} else {
return foldFF();
}


>
> I do not know, An "if" constructs returns a BOOLEAN value, it is either
> true or false, so the "else" cares about the false condition, but there
> are NO MORE conditions...
>
> But with C++ you really never know...
>

Yes, you know fine - C++ is not /that/ difficult. "if constexpr" gets
structured the same way as "if" does. And people get it wrong
sometimes, just as they get C wrong and any other language wrong sometimes.

(C++ has plenty of hard bits - like knowing when to use "decltype" - but
this is not one of them.)

bartc

unread,
Dec 9, 2017, 12:47:00 PM12/9/17
to
That doesn't account for the { on the 'auto...' line that doesn't have a
corresponding }.

However the purpose of 'if constexpr...' seems clear enough even to me.
Whatever branch of 'if constexpr' happens to be true at compile-time (in
a particular expansion of the template code), is compiled
unconditionally, and the other branches ignored.

--
bartc

David Brown

unread,
Dec 9, 2017, 1:01:09 PM12/9/17
to
I hadn't included that part of the function definition. But certainly
there needs to be a final } at the end to match the opening { at the
start of the function.

> However the purpose of 'if constexpr...' seems clear enough even to me.
> Whatever branch of 'if constexpr' happens to be true at compile-time (in
> a particular expansion of the template code), is compiled
> unconditionally, and the other branches ignored.
>

Yes.

The idea is to reduce the need for SFINAE, complicated template
specialisations, and std::enable_if expressions. These are all quite
complicated, and it takes a lot of thought to understand them - "if
constexpr" is a good deal easier to grasp and to use.

"if constexpr" also reduces the need for pre-processor conditional
compilation - in C++, it is generally considered better to avoid
pre-processor solutions when there are alternatives.
0 new messages