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

Substitution failure can be an error

139 views
Skip to first unread message

Alf P. Steinbach

unread,
Nov 18, 2019, 12:49:37 PM11/18/19
to
As the title says, substitution failure can be an error:


#include <iostream>
#include <initializer_list>
#include <type_traits>
using namespace std;

template< class Value >
auto is_in( const initializer_list<Value>& list, const Value v )
-> bool
{ return false; }

//-----------------------------------
template< class Int >
struct S
{
using U = make_unsigned_t<Int>;
U m;

S( Int x, Int ): m( U( x ) ) {}
};

template< class Int >
auto is_in( const S<Int>& s, const Int v )
-> bool
{ return true; }

auto main()
-> int
{ return 100 + is_in( {&cout, &cerr}, &clog ); }


For now I've just used a `std::enable_if` to restrict `S` to integral
types, but I don't feel that this can be the best solution.

Like, it feels like a kludge, somewhat dirty.


- Alf

Vir Campestris

unread,
Nov 18, 2019, 4:54:37 PM11/18/19
to
On 18/11/2019 17:49, Alf P. Steinbach wrote:
> As the title says, substitution failure can be an error:

Most interesting post for weeks - and I don't understand it :(

It would help if I had a modern compiler to hand of course - but playing
with an online one does give me an error.

Are you sure it isn't a compiler bug? The error from clang is nothing
like the one from GCC.

Andy

Sam

unread,
Nov 18, 2019, 6:12:29 PM11/18/19
to
This is not a substitution failure.

SFINAE does not mean "any error that occurs when instantiating a template is
not really an error".

Substitution succeeded, and the template parameters were deduced. But there
was an error instantiating the class's constructor.

When you crammed enable_if in there, that prevented the compiler from
figuring out which real, live, breathing types to substitute for the
template parameters. Here, it figured out what matches "Int". Then things
went on their merry way, but the instantiated template turned out to be ill-
formed.

Melzzzzz

unread,
Nov 18, 2019, 10:53:21 PM11/18/19
to
On 2019-11-18, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> As the title says, substitution failure can be an error:
>
>
> #include <iostream>
> #include <initializer_list>
> #include <type_traits>
> using namespace std;
>
> template< class Value >
> auto is_in( const initializer_list<Value>& list, const Value v )
> -> bool
> { return false; }

why not just auto? What's the point of both auto and return type?



--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Alf P. Steinbach

unread,
Nov 19, 2019, 6:48:28 AM11/19/19
to
On 19.11.2019 04:53, Melzzzzz wrote:
> On 2019-11-18, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> As the title says, substitution failure can be an error:
>>
>>
>> #include <iostream>
>> #include <initializer_list>
>> #include <type_traits>
>> using namespace std;
>>
>> template< class Value >
>> auto is_in( const initializer_list<Value>& list, const Value v )
>> -> bool
>> { return false; }
>
> why not just auto? What's the point of both auto and return type?

It may be that you're asking about the syntax.

Well, `auto f() -> T` for /trailing return type/ was introduced in C++11.

Now that you have a name you can look it up.

`auto` for /deduced return type/, like `auto f() { return 3; }` was
introduced in C++14, almost like sabotage of the C++11 syntax.

Apparently support for `auto auto`, writing `auto f() -> auto { return
3; }` in order to specify deduced return type explicitly, was introduced
in C++17. But of this I'm less sure. Even though compilers I've tried
accept the syntax I don't even know, 100%, that it's valid C++.

---

It may alternatively be that you're asking why most C++ programmers
still generally specify return types instead of using deduced return type.

A deduced return type can be very convenient for e.g. a `begin()` member
function that just defers the work to some member container's `begin()`.

But a deduced return type can in the worst case mean that you have to
delve to the bottom of an arbitrary long call chain in order to find out
what the return type, that the compiler knows, is. On the way you may
have to do overload resolution and template instantiation just like the
compiler, to figure out where these calls go. You may have to use a
debugger.

That's just a waste of time for the programmer.

And so it's strongly counter-productive to use this feature in general.

---

If you meant the second interpretation, then I think a better question
is whether there are programmers who regularly use deduced return type,
and if so, what on Earth makes them do that counter-productive thing?

In my opinion, if they exist, then they're likely a collection of total
incompetents, the genuinely insane and maybe herd followers, just as
with any group that does irrational things: some are insane, some don't
understand any of it, and some (in religion that's most) follow the herd
in order to derive social advantages, or avoid social disadvantage.

But I would guess that any group of C++ programmers using deduced return
type is not yet large enough that there would be any herd followers.


- Alf

Melzzzzz

unread,
Nov 19, 2019, 2:48:27 PM11/19/19
to
Just one question. What's the point of auto then?
>
>
> - Alf

Alf P. Steinbach

unread,
Nov 19, 2019, 3:31:59 PM11/19/19
to
On 19.11.2019 20:48, Melzzzzz wrote:
>
> Just one question. What's the point of auto then?

It's still unclear what you're asking about. You quoted everything to be
sure not to give any indication. I snipped all that.

If you're asking about the syntax, then in C++11 the point was that
`auto` was an available keyword to use in the new syntax. The original
meaning in C, of automatic storage, was covered by that being the
default. For the new syntax, trailing return type, it was not mnemonic,
but it was deemed better than the other available keyword, `register`.

register foo() -> int

Nah.

But the committee could have chosen to use operator notation, like the
lambda notation:

[] foo() -> int

Then they'd have had a nice notation where the difference between a
named function and a basic unnamed one (lambda), would simply be that no
name was provided for the unnamed one. One conceptual problem with this
scheme is that the named functions would be declarations while the
unnamed ones would be expressions. I don't offhand see that the
possibility of `[]` occurring in a possible-declaration context would be
problematic for a compiler, e.g. leading to parse ambiguities, but maybe
it would -- the committee includes folks from compiler vendors, folks
who know a lot about the inner workings. There is however a problem of
similar notation implying similar functionality. And it doesn't make
much sense to specify captures for a named function declaration.

Alternatively the committee could have chosen to open up for new kinds
of identifiers, such as `#foo` and `$foo`, to use as new keywords (the
problems with these is that they can introduce conflicts with existing
preprocessing, in particular #foo with the *nix convention for shell
scripts). Or they could have chosen to introduce contextual keywords,
keywords that are only keywords in certain contexts, which would reduce
or eliminate breakage of existing code. Or they could have chosen to
simply add new keywords as they've now done in C++20 (there's a host of
them). Or they could go for ugliness, like `__foo`, which is safe and
readable but just ugly. They chose neither of these approaches.

I.e. they were still very very conservative for C++11, going for
technical safety instead of readability where readability mattered, and
now in C++20 for more esoteric little used features they feel more free. :(

- Alf

Melzzzzz

unread,
Nov 19, 2019, 4:21:06 PM11/19/19
to
On 2019-11-19, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> On 19.11.2019 20:48, Melzzzzz wrote:
>>
>> Just one question. What's the point of auto then?
>
> It's still unclear what you're asking about. You quoted everything to be
> sure not to give any indication. I snipped all that.
>
> If you're asking about the syntax, then in C++11 the point was that
> `auto` was an available keyword to use in the new syntax. The original
> meaning in C, of automatic storage, was covered by that being the
> default. For the new syntax, trailing return type, it was not mnemonic,
> but it was deemed better than the other available keyword, `register`.
>
> register foo() -> int

I think that all that matter is exercize in futility. We already have
function syntax, this one has sence only on unspecified return type,
for what auto keyword is handy. I will never use it in my code as it can
serve just to bring confusion...

Alf P. Steinbach

unread,
Nov 19, 2019, 4:51:20 PM11/19/19
to
On 19.11.2019 22:20, Melzzzzz wrote:
> On 2019-11-19, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> On 19.11.2019 20:48, Melzzzzz wrote:
>>>
>>> Just one question. What's the point of auto then?
>>
>> It's still unclear what you're asking about. You quoted everything to be
>> sure not to give any indication. I snipped all that.
>>
>> If you're asking about the syntax, then in C++11 the point was that
>> `auto` was an available keyword to use in the new syntax. The original
>> meaning in C, of automatic storage, was covered by that being the
>> default. For the new syntax, trailing return type, it was not mnemonic,
>> but it was deemed better than the other available keyword, `register`.
>>
>> register foo() -> int
>
> I think that all that matter is exercize in futility. We already have
> function syntax, this one has sence only on unspecified return type,
> for what auto keyword is handy. I will never use it in my code as it can
> serve just to bring confusion...

Whether that is likely true or not, you are now feeling competent to
evaluate something that you have just shown you didn't understand
moments ago.

It's unlikely that you have gained a full understanding in so short a
time, and committing to an evaluation this early makes the climb towards
learning more, more difficult.

If instead you keep an open mind, defer the rash impulse to evaluate,
you may learn new things faster.


- Alf

Melzzzzz

unread,
Nov 19, 2019, 4:58:30 PM11/19/19
to
On 2019-11-19, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> On 19.11.2019 22:20, Melzzzzz wrote:
>> On 2019-11-19, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>>> On 19.11.2019 20:48, Melzzzzz wrote:
>>>>
>>>> Just one question. What's the point of auto then?
>>>
>>> It's still unclear what you're asking about. You quoted everything to be
>>> sure not to give any indication. I snipped all that.
>>>
>>> If you're asking about the syntax, then in C++11 the point was that
>>> `auto` was an available keyword to use in the new syntax. The original
>>> meaning in C, of automatic storage, was covered by that being the
>>> default. For the new syntax, trailing return type, it was not mnemonic,
>>> but it was deemed better than the other available keyword, `register`.
>>>
>>> register foo() -> int
>>
>> I think that all that matter is exercize in futility. We already have
>> function syntax, this one has sence only on unspecified return type,
>> for what auto keyword is handy. I will never use it in my code as it can
>> serve just to bring confusion...
>
> Whether that is likely true or not, you are now feeling competent to
> evaluate something that you have just shown you didn't understand
> moments ago.

I undertstood it perfectly since auto keyword brought me for purpose
auto return type.
I understand that you like new syntax for functions more, but I don't
call it C++...

>
> It's unlikely that you have gained a full understanding in so short a
> time, and committing to an evaluation this early makes the climb towards
> learning more, more difficult.

What short time? C++14 was released years ago...


> If instead you keep an open mind, defer the rash impulse to evaluate,
> you may learn new things faster.

This is not matter of open mind rather C++. That syntax is not C++
rather SomeOtherLanguage...
>
>
> - Alf

David Brown

unread,
Nov 20, 2019, 3:19:56 AM11/20/19
to
On 19/11/2019 22:20, Melzzzzz wrote:
> On 2019-11-19, Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> On 19.11.2019 20:48, Melzzzzz wrote:
>>>
>>> Just one question. What's the point of auto then?
>>
>> It's still unclear what you're asking about. You quoted everything to be
>> sure not to give any indication. I snipped all that.
>>
>> If you're asking about the syntax, then in C++11 the point was that
>> `auto` was an available keyword to use in the new syntax. The original
>> meaning in C, of automatic storage, was covered by that being the
>> default. For the new syntax, trailing return type, it was not mnemonic,
>> but it was deemed better than the other available keyword, `register`.
>>
>> register foo() -> int
>
> I think that all that matter is exercize in futility. We already have
> function syntax, this one has sence only on unspecified return type,
> for what auto keyword is handy. I will never use it in my code as it can
> serve just to bring confusion...
>

I expect that most people will continue to use the normal C++ function
syntax for the majority of their code. "auto" functions certainly have
their use cases, and where it is useful, it is very useful:

template <class A, class B>
auto sum(A a, B b) -> decltype(a + b)
{
return a + b;
}

You can't do write that as neatly or as well without "auto". This is
why the trailing return type syntax was invented.

It can also be convenient for simple, local functions using return type
deduction:

auto foo(int a)
{
return a * 1.2345;
}

This is especially true for returning more complicated types (iterators,
lambdas, etc.) - just like the use of "auto" for variables.

But I really do not see any benefit of writing:

auto foo(int a) -> double
{
return a * 1.2345;
}

It adds nothing to the language or the code. (Clearly the language had
to allow it, in order to allow useful cases, but that does not mean you
have to /use/ it.) The only argument I have heard in its favour is
"consistency" - but it is a foolish consistency, IMHO, and inconsistent
with all the rest of C++ code.

Time will tell - it is the only way to find out if this syntax becomes
the fashion or not.

(It would be a little different if a new function-specific keyword had
been added, like "def" or "func". Then there would be an advantage in
having it, making the function definition stand out more - I know that
is something that some people would prefer. But it would have to be a
unique keyword - another overload of "auto" does not help here.)


Christian Gollwitzer

unread,
Nov 20, 2019, 5:12:20 AM11/20/19
to
Am 19.11.19 um 21:31 schrieb Alf P. Steinbach:
> On 19.11.2019 20:48, Melzzzzz wrote:
>>
>> Just one question. What's the point of auto then?
>
> It's still unclear what you're asking about. You quoted everything to be
> sure not to give any indication. I snipped all that.
>
> If you're asking about the syntax, then in C++11 the point was that
> `auto` was an available keyword to use in the new syntax. The original
> meaning in C, of automatic storage, was covered by that being the
> default. For the new syntax, trailing return type, it was not mnemonic,
> but it was deemed better than the other available keyword, `register`.
>
>     register foo() -> int
>
> Nah.
>
> But the committee could have chosen to use operator notation, like the
> lambda notation:
>
>    [] foo() -> int
>

Actually, they could have chosen to omit the type means "auto". In old
C, omitting the type meant "int", which is obviously not useful any
longer. Making "no type" into "auto" could make C++ closer to other
modern languages. I.e.

f(x, y) { return x+y; }

could become

auto f(auto x, auto y) { return x+y; }

which is

template <typename Tx, Ty>
auto f(Tx, x, Ty y) { return x+y; }


without all the cruft that the compiler can figure out by itself.

Christian

Öö Tiib

unread,
Nov 20, 2019, 5:16:30 AM11/20/19
to
On Wednesday, 20 November 2019 10:19:56 UTC+2, David Brown wrote:
>
> But I really do not see any benefit of writing:
>
> auto foo(int a) -> double
> {
> return a * 1.2345;
> }

No way out of it. It is in language so we all must be capable
to read it (even if we dislike it and refuse to write it).

What I think is that it is half-solution of moving C++ from type
being smeared around name towards type last. Lot of other
languages, (including number of C-like languages) have
type last:

function foo(a: integer): double;

Designers of those languages considered it more clear
and readable.

Other example from C++: Many consider using "using" instead of
"typedef" more readable for declaring type aliases.
Typedef:

typedef double(*Portal)[4];
typedef std::string Contact;
typedef std::vector<Portal> Portals;
typedef std::map<Contact, Portals> PortalsOfContact;

Using:

using Portal = double(*)[4];
using Contact = std::string;
using Portals = std::vector<Portal>;
using PortalsOfContact = std::map<Contact, Portals>;

Nah ... matter of taste? However the result that we have both in
language is kind of anarchistic, since all users of it must be
capable to understand both when reading and when writing
have to pick (or to ask what to pick or to argue it clear what
we pick).

Also it is only half-solution since when declaring variables,
parameters or members we have type that is smeared around
name anyway and there are no alternatives to have it last.

> Time will tell - it is the only way to find out if this syntax becomes
> the fashion or not.

My glass ball says that like it is it will just troll up discussions of
readability (instead of discussions of actual technical problems)
forever. Perhaps it is sort of cheap publicity stunt:
fashion controversy -> novice questions -> heated discussions
-> more hits -> more popularity. From engineering perspective
that all is utterly worthless.

However if a way to have "type last" for parameters, members
and variables will also be added by some C++2013 or C++2016
then I will switch over into proponent of that style too. ;-)

Öö Tiib

unread,
Nov 20, 2019, 7:26:11 AM11/20/19
to
On Wednesday, 20 November 2019 12:12:20 UTC+2, Christian Gollwitzer wrote:
>
> template <typename Tx, Ty>
> auto f(Tx, x, Ty y) { return x+y; }
>
> without all the cruft that the compiler can figure out by itself.

Oh so easy is to write wrappers around operator+.
But what is the point of it? There must be something more complicated
than operator+.

So lets say that we have f that is result of something more complicated.
What about callers of f? Lets say its caller gets several values
also from similar functions/members that return who knows what
and has to return a mapping from all v-s to what f returns there.
Something like:

auto makeMapping(int i)
{
using PromoterHapperFOfVacuole = ???; // what it is?

PromoterHapperFOfVacuole ret;

for (auto v = getFirstVacuole(i); v.isUseful(); v = v.getNext()) {
// here we use your f
ret[v] = f(producePromoter(v.vaginulate(),hatchHapper(p.glaze(), v.jabbered()));
}
return ret;
}

What *is* the type of mapping? From where to take
that unavoidable "cruft" here? Reverse engineer
somehow from those getFirstVacuole etc? How?
Also sorry for using more meaningful function names than f.

Öö Tiib

unread,
Nov 20, 2019, 9:05:46 AM11/20/19
to
On Wednesday, 20 November 2019 14:26:11 UTC+2, Öö Tiib wrote:
> On Wednesday, 20 November 2019 12:12:20 UTC+2, Christian Gollwitzer wrote:
> >
> > template <typename Tx, Ty>
> > auto f(Tx, x, Ty y) { return x+y; }
> >
> > without all the cruft that the compiler can figure out by itself.
>
> Oh so easy is to write wrappers around operator+.
> But what is the point of it? There must be something more complicated
> than operator+.
>
> So lets say that we have f that is result of something more complicated.
> What about callers of f? Lets say its caller gets several values
> also from similar functions/members that return who knows what
> and has to return a mapping from all v-s to what f returns there.
> Something like:
>
> auto makeMapping(int i)
> {
> using PromoterHapperFOfVacuole = ???; // what it is?
>
> PromoterHapperFOfVacuole ret;
>
> for (auto v = getFirstVacuole(i); v.isUseful(); v = v.getNext()) {
> // here we use your f
> ret[v] = f(producePromoter(v.vaginulate(),hatchHapper(p.glaze(), v.jabbered()));

Sorry did not try it ... I meant something like:

auto p = producePromoter(v.vaginulate(), i);
ret[v] = f(p, hatchHapper(p.glaze(), v.jabbered()));

Scott Lurndal

unread,
Nov 20, 2019, 9:14:02 AM11/20/19
to
=?UTF-8?B?w5bDtiBUaWli?= <oot...@hot.ee> writes:
>On Wednesday, 20 November 2019 10:19:56 UTC+2, David Brown wrote:
>>
>> But I really do not see any benefit of writing:
>>
>> auto foo(int a) -> double
>> {
>> return a * 1.2345;
>> }
>
>No way out of it. It is in language so we all must be capable
>to read it (even if we dislike it and refuse to write it).
>
>What I think is that it is half-solution of moving C++ from type
>being smeared around name towards type last. Lot of other
>languages, (including number of C-like languages) have
>type last:
>
> function foo(a: integer): double;
>
>Designers of those languages considered it more clear
>and readable.

Did they? Or were they simply following some earlier example?

For example, ALGOL 68:
proc abs max = ([,]real a, ref real y, ref int i, k)real:


ALGOL 60 was more like KNR C:

procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k);
value n, m; array a; integer n, m, i, k; real y;

Öö Tiib

unread,
Nov 20, 2019, 11:34:27 AM11/20/19
to
On Wednesday, 20 November 2019 16:14:02 UTC+2, Scott Lurndal wrote:
> =?UTF-8?B?w5bDtiBUaWli?= <oot...@hot.ee> writes:
> >On Wednesday, 20 November 2019 10:19:56 UTC+2, David Brown wrote:
> >>
> >> But I really do not see any benefit of writing:
> >>
> >> auto foo(int a) -> double
> >> {
> >> return a * 1.2345;
> >> }
> >
> >No way out of it. It is in language so we all must be capable
> >to read it (even if we dislike it and refuse to write it).
> >
> >What I think is that it is half-solution of moving C++ from type
> >being smeared around name towards type last. Lot of other
> >languages, (including number of C-like languages) have
> >type last:
> >
> > function foo(a: integer): double;
> >
> >Designers of those languages considered it more clear
> >and readable.
>
> Did they? Or were they simply following some earlier example?

Certainly there were plenty of examples of every kind.

I meant designers of newer C-like languages Go, Rust and
Swift.

They switched to type being last in declarations while
all previous attempts of "better" C, (C++, Objective-C,
Java, D and C#) had type first or around name like in C?

>
> For example, ALGOL 68:
> proc abs max = ([,]real a, ref real y, ref int i, k)real:
>
>
> ALGOL 60 was more like KNR C:
>
> procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k);
> value n, m; array a; integer n, m, i, k; real y;

Sure there have been also plenty of mixed and inconsistent
examples.

Manfred

unread,
Nov 20, 2019, 12:46:43 PM11/20/19
to
I'll steer away from the discussion about trailing return type (which
has been discussed ad nauseam)

Substitution failure in this case happens for instantiation of a class
member (m), after specialization of the template S.
So it looks like the error occurs too late to be eliminated by SFINAE.

I didn't check the standard, but Bjarne's book on SFINAE says that the
compiler eliminates a candidate if the associated substitution would
lead to a "template specialization that would be nonsensical" - now,
define "nonsensical".
He says: "A template specialization is considered nonsensical if it
would lead to a type error." And further on that only declarations are
considered, neither function definitions nor definitions of class
members are considered.

So, slippery, but we can say that SFINAE is not a fully baked tool for
template selection. He himself suggests enable_if as a more specific
tool for the task.
I would say that even if enable_if looks dirty, this is because of its
syntactic ugliness, and it is probably the right choice.

Alf P. Steinbach

unread,
Nov 21, 2019, 12:03:09 AM11/21/19
to
On 20.11.2019 18:46, Manfred wrote:
> Bjarne's book on SFINAE

Uh, which book?

I remember introducing Bjarne to the term in a mail exchange, but it's
apparently not in my GMail so it must be have been before July 2006.

- Alf

David Brown

unread,
Nov 21, 2019, 6:34:55 AM11/21/19
to
On 20/11/2019 17:34, Öö Tiib wrote:
> On Wednesday, 20 November 2019 16:14:02 UTC+2, Scott Lurndal wrote:
>> =?UTF-8?B?w5bDtiBUaWli?= <oot...@hot.ee> writes:
>>> On Wednesday, 20 November 2019 10:19:56 UTC+2, David Brown wrote:
>>>>
>>>> But I really do not see any benefit of writing:
>>>>
>>>> auto foo(int a) -> double
>>>> {
>>>> return a * 1.2345;
>>>> }
>>>
>>> No way out of it. It is in language so we all must be capable
>>> to read it (even if we dislike it and refuse to write it).
>>>
>>> What I think is that it is half-solution of moving C++ from type
>>> being smeared around name towards type last. Lot of other
>>> languages, (including number of C-like languages) have
>>> type last:
>>>
>>> function foo(a: integer): double;
>>>
>>> Designers of those languages considered it more clear
>>> and readable.
>>
>> Did they? Or were they simply following some earlier example?
>
> Certainly there were plenty of examples of every kind.
>
> I meant designers of newer C-like languages Go, Rust and
> Swift.
>
> They switched to type being last in declarations while
> all previous attempts of "better" C, (C++, Objective-C,
> Java, D and C#) had type first or around name like in C?
>

Fair enough for the facts of these languages - they have the type coming
last. (I am taking your word for that - I don't know the details of
them.) What is your evidence for the reason for this choice? You say
the "designers of those languages considered it more clear and readable"
- is that just your guess, or have they published rationales or other
information explaining their reasoning? (I hope it is the later, as
those could be very interesting reads.)


Öö Tiib

unread,
Nov 21, 2019, 8:29:42 AM11/21/19
to
I sometimes try programming languages (for fun puzzle with new tool)
so I'm 100% sure that all of those (plus also Kotlin) use "type right" syntax.
Also type can be often implicitly deducible and then there are just nothing
(no "auto") needed.

> What is your evidence for the reason for this choice? You say
> the "designers of those languages considered it more clear and readable"
> - is that just your guess, or have they published rationales or other
> information explaining their reasoning? (I hope it is the later, as
> those could be very interesting reads.)

For general public the best explanation that I have read was blogged
by Rob Pike about Go:
<https://blog.golang.org/gos-declaration-syntax>
Note that it is actually matter of taste (again) so your mileage may vary
from strongly disagree to fully agree but the argumentation felt relatively
solid there.

My own opinion is that C's declarations are simpler for parsers to parse
but Go/Rust/Swift/Kotlin declarations feel easier for human to to type
and to read.

Manfred

unread,
Nov 21, 2019, 9:50:26 AM11/21/19
to
read: Bjarne's book says on SFINAE ...
The C++ Programming Language (4th Edition), p. 692

However, it is curious that the following still fails:

template< class Int, class UInt = make_unsigned_t<Int> >
struct S
{
// using UInt = make_unsigned_t<Int>;
UInt m;

S( Int x, Int ): m( UInt( x ) ) {}
};

The error is still about "invalid use of incomplete type", which sounds
like a type error to me.

while

template< class Int, typename = typename
enable_if<is_integral<Int>::value>::type
>
struct S
{
using UInt = make_unsigned_t<Int>;
UInt m;

S( Int x, Int ): m( UInt( x ) ) {}
};

seems to work fine.

David Brown

unread,
Nov 21, 2019, 9:59:13 AM11/21/19
to
I too like to try new languages - when I get the time!

> Also type can be often implicitly deducible and then there are just nothing
> (no "auto") needed.
>
>> What is your evidence for the reason for this choice? You say
>> the "designers of those languages considered it more clear and readable"
>> - is that just your guess, or have they published rationales or other
>> information explaining their reasoning? (I hope it is the later, as
>> those could be very interesting reads.)
>
> For general public the best explanation that I have read was blogged
> by Rob Pike about Go:
> <https://blog.golang.org/gos-declaration-syntax>
> Note that it is actually matter of taste (again) so your mileage may vary
> from strongly disagree to fully agree but the argumentation felt relatively
> solid there.

I'll read it - thanks for the link.

>
> My own opinion is that C's declarations are simpler for parsers to parse
> but Go/Rust/Swift/Kotlin declarations feel easier for human to to type
> and to read.
>

Many of the humans here find C's declaration easy to parse from long
habit - it's always difficult to judge such inherently subjective issues.

Vir Campestris

unread,
Nov 22, 2019, 4:46:45 PM11/22/19
to
That's interesting. That sound as if you're on my side of the "almost
always auto" argument I've heard bandied about - not least by the guy
who owns our coding standards :(

The argument is that given "x=4.2" you _know_ that x is a double,
there's no point in saying so.

I don't like it - that variable ought to be a type you know, and you
should say so. I find it easier to _read_ code that explicitly states
the types. OTOH, I've experimented, and it's easier to _write_ code that
uses auto everywhere.

When I read "auto x = somefunction()" I don't know what x is. Unless I
look at the declaration. Which if I'm unlucky is one of several
overloads with template type deduction from the parameters.

But IMHO reading matters more. You'll only write it once.

Andy

Jorgen Grahn

unread,
Nov 23, 2019, 4:29:15 AM11/23/19
to
On Fri, 2019-11-22, Vir Campestris wrote:
> On 19/11/2019 11:48, Alf P. Steinbach wrote:
[...]

> That's interesting. That sound as if you're on my side of the "almost
> always auto" argument I've heard bandied about - not least by the guy
> who owns our coding standards :(

"Use auto everywhere, and let your IDE tell you what the type is with
a tooltip". I remember asking about that here some years ago -- what
people thought of that advise. I don't remember a clear outcome, except
someone predicted we'd see a few years of auto abuse, followed by a
backlash.

> The argument is that given "x=4.2" you _know_ that x is a double,
> there's no point in saying so.
>
> I don't like it - that variable ought to be a type you know, and you
> should say so. I find it easier to _read_ code that explicitly states
> the types. OTOH, I've experimented, and it's easier to _write_ code that
> uses auto everywhere.

Reminds me of why I don't like Python so much: I find it easy to write
the code, but when I revisit it I have to backtrack through my own
duck typing stunts in order to find out what it actually does.

> When I read "auto x = somefunction()" I don't know what x is. Unless I
> look at the declaration. Which if I'm unlucky is one of several
> overloads with template type deduction from the parameters.
>
> But IMHO reading matters more. You'll only write it once.

I tend to agree. I use auto, but try to be careful so it won't be a
problem when I revisit the code, like my duck typing exercises are in
Python.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

bol...@nowhere.co.uk

unread,
Nov 23, 2019, 12:23:45 PM11/23/19
to
On 23 Nov 2019 09:29:01 GMT
Jorgen Grahn <grahn...@snipabacken.se> wrote:
>On Fri, 2019-11-22, Vir Campestris wrote:
>> On 19/11/2019 11:48, Alf P. Steinbach wrote:
>[...]
>
>> That's interesting. That sound as if you're on my side of the "almost
>> always auto" argument I've heard bandied about - not least by the guy
>> who owns our coding standards :(
>
>"Use auto everywhere, and let your IDE tell you what the type is with
>a tooltip". I remember asking about that here some years ago -- what
>people thought of that advise. I don't remember a clear outcome, except
>someone predicted we'd see a few years of auto abuse, followed by a
>backlash.

Its pretty stupid advice since not everyone uses or wants to use an IDE.
If find they just get in the way and offer little over a decent programmers
editor and standard command line tools on *nix. And as for Visual Shitshow on
Windows, god almighty , how does anyone use that obtuse piece of garbage
without going insane.


Alf P. Steinbach

unread,
Nov 23, 2019, 6:26:27 PM11/23/19
to
It requires /reading/ with analysis and comprehension as opposed to just
looking at.

And it fails for

auto hm = 0x1'0000'0000;

This type depends on the compiler.


> I don't like it - that variable ought to be a type you know, and you
> should say so. I find it easier to _read_ code that explicitly states
> the types. OTOH, I've experimented, and it's easier to _write_ code that
> uses auto everywhere.
>
> When I read "auto x = somefunction()" I don't know what x is. Unless I
> look at the declaration. Which if I'm unlucky is one of several
> overloads with template type deduction from the parameters.
>
> But IMHO reading matters more. You'll only write it once.

I prefer that the type is generally specified explicitly in a
declaration, either on the left side or explicitly in the initializer.

Exception: types that are effectively or formally unspecified, such as
iterator type or the type of an iostream manipulator.

Example, display the ASCII code:


#include <ctype.h> // ::isprint
#include <iomanip> // std::setw
#include <iostream>
#include <limits.h> // CHAR_MIN, UCHAR_MAX

using Byte = unsigned char;

auto is_noncontrol_ascii_char( const int code )
-> bool
{ return (code > CHAR_MIN and code < UCHAR_MAX and ::isprint( Byte( code
) ); }

auto main()
-> int
{
using std::cout, std::endl, std::left, std::setw;
constexpr auto& hex_digits = "0123456789abcdef";

const auto field = setw( 4 );
cout << left;

// Column headers.
cout << field << "";
for( int x = 0; x < 16; ++x ) { cout << field << hex_digits[x]; }
cout << endl;
cout << endl; // Spacer line to make the header row
stand out as such.

// Main table with a row header column to the left.
for( int y = 0; y < 8; ++y ) {
cout << field << hex_digits[y];
for( int x = 0; x < 16; ++x ) {
const int code = 16*y + x;
const auto ch = char( is_noncontrol_ascii_char( code )?
code: ascii::del );
cout << field << ch;
}
cout << endl;
}
}


- Alf

Alf P. Steinbach

unread,
Nov 23, 2019, 6:28:32 PM11/23/19
to
On 24.11.2019 00:26, Alf P. Steinbach wrote:
> [snip]
Oops. ">=", "<=". Oh well.

- Alf

Alf P. Steinbach

unread,
Nov 23, 2019, 6:45:24 PM11/23/19
to
On 24.11.2019 00:26, Alf P. Steinbach wrote:
> code that wouldn't even compile

Good idea to compile before posting, yes!

So here's the example, with a few instances of `auto` declarations of
things where either the type is irrelevant, or already explicit:


#include <ctype.h> // ::isprint
#include <iomanip> // std::setw
#include <iostream>
#include <limits.h> // CHAR_MIN, UCHAR_MAX

using Byte = unsigned char;

auto is_noncontrol_ascii_char( const int code )
-> bool
{ return (code >= CHAR_MIN and code <= UCHAR_MAX and ::isprint( Byte(
code ) ) ); }

auto main()
-> int
{
using std::cout, std::endl, std::left, std::setw;
constexpr auto& hex_digits = "0123456789abcdef";

const auto field = setw( 4 );
const auto ascii_del = char( 127 );

cout << left;

// Column headers.
cout << field << "";
for( int x = 0; x < 16; ++x ) { cout << field << hex_digits[x]; }
cout << endl;
cout << endl; // Spacer line to make the header row
stand out as such.

// Main table with a row header column to the left.
for( int y = 0; y < 8; ++y ) {
cout << field << hex_digits[y];
for( int x = 0; x < 16; ++x ) {
const int code = 16*y + x;
const auto ch = char( is_noncontrol_ascii_char( code )?
code: ascii_del );

bol...@nowhere.co.uk

unread,
Nov 24, 2019, 5:47:12 AM11/24/19
to
On Sun, 24 Nov 2019 00:26:14 +0100
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>auto main()
> -> int

And the point of writing that instead of

int main()

is what exactly? Other than showing off of course.


Melzzzzz

unread,
Nov 24, 2019, 8:37:22 AM11/24/19
to
He doesn't like C++ ;)

bol...@nowhere.co.uk

unread,
Nov 25, 2019, 6:08:24 AM11/25/19
to
On Sun, 24 Nov 2019 13:37:11 GMT
Melzzzzz <Melz...@zzzzz.com> wrote:
>On 2019-11-24, bol...@nowhere.co.uk <bol...@nowhere.co.uk> wrote:
>> On Sun, 24 Nov 2019 00:26:14 +0100
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>>>auto main()
>>> -> int
>>
>> And the point of writing that instead of
>>
>> int main()
>>
>> is what exactly? Other than showing off of course.
>
>He doesn't like C++ ;)

He certainly doesn't like clear code. Devs like him piss me off - they make
simple things complicated for no reason other than to show boat and/or make
it hard for others to maintain the code and so keep themselves in a job.

Tim Rentsch

unread,
Nov 28, 2019, 3:47:01 PM11/28/19
to
I don't have a lot of experience with "auto" in C++, but a fair
amount of experience with type inference (and not needing type
annotations in many cases) in other programming languages. I
don't have any hard and fast rule, but generally I find it works
well to give an explicit type annotation only in those cases
where it's important to know exactly what the type is. Probably
this rule carries over into C++ reasonably well, although the
two situations are not completely parallel. In particular, C++
doesn't have partial types, except maybe for arrays -- it's
pretty much all or nothing, either a completely specified type
or none at all; there is no way in C++ to say a type is "a list
of something, but I won't say what the something is". But I
think the general rule is still good in the C++ domain.
0 new messages