An implementation of enhanced auto deduction and abbreviated template syntax using Clang

208 views
Skip to first unread message

Faisal Vali

unread,
Mar 3, 2015, 9:39:49 PM3/3/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org
In the hopes of soliciting constructive feedback, if anyone has the
time or the interest to play with a patched up Clang that implements
enhanced auto deduction & abbreviated template syntax from the
concepts ts, here it is:

https://github.com/faisalv/clang/tree/enhanced-auto-c%2B%2B1z .

The last line of the README file tells you the subversion revision of
LLVM to use.

For examples of test cases that successfully compile, please refer to:
-- https://github.com/faisalv/clang/blob/enhanced-auto-c%2B%2B1z/test/CXX/auto/cxx1z-auto-vars-generalized.cpp
-- https://github.com/faisalv/clang/blob/enhanced-auto-c%2B%2B1z/test/CXX/auto/cxx1z-abbreviated-templates.cpp

I would certainly appreciate the feedback!

1) Enhanced-Auto Deduction:

pair<auto...> f() { return make_pair([] { }, [] { }); }
vector<auto> v = vector<int>();

2) Abbreviated Template Syntax:
void f(auto) <=> template<class T> void f(T);


A few, perhaps not so obvious or interesting, technicalities:

a) The equivalence of templates when it comes to trailing return
types in function pointer parameters is based on the order of the
'auto' that signifies a placeholder, not just the appearance of an
auto in the declaration-specifier of a parameter:

template<class R, class P> void f( R(P) ); // #1
template<class P, class R> void f( R(P) ); // #2 (order of
templ-params flipped)

template<class R, class P> void f( auto (P)->R); // equivalent to
#1, not abbreviated.
void f(auto(auto)); // equivalent to #1
void f(auto (auto) -> auto); // equivalent to #2
// the trailing return type auto
// identifies a
template parameter
template<class R> void f(R(auto); // equivalent to #1
template<class P> void f(auto(P)); // equivalent to #2

b) variadic auto
Once an ellipsis is seen as part of the declarator, all contained
auto placeholders get transformed into parameter packs.
void f(auto (*...)(auto) -> std::tuple<auto, std::pair<auto, auto>...>);
Note there are 4 deducible template parameter packs above.

c) multi abbreviated template declarations
void f(auto), g(auto);
are allowed - the above declares two function templates.

d) template aliases desugar their types *after* each auto has been
identified as a placeholder (and so must be deduced)

template<class T> using Int = int;
Int<auto> i = 3; // Is an error, auto must be deducible.

e) generic lambda's as default arguments work with abbreviated template syntax:
void f(int (*)(int) = [](auto a) { return a; }, auto b = decltype(b){});
f<float*>(); // OK

f) variable templates and enhanced auto deduction interact as expected:
template<class T> pair<auto...> (*vfp)(auto...) = [](T t1, T* t2)
{ return make_pair(t1, t2); };

Thanks!
Faisal Vali

Gabriel Dos Reis

unread,
Mar 3, 2015, 10:45:05 PM3/3/15
to <std-proposals@isocpp.org>, std-dis...@isocpp.org, c++st...@accu.org
Should we declare "auto f(auto) -> auto" an excess in sophism?

-- Gaby
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
>

Faisal Vali

unread,
Mar 3, 2015, 11:04:37 PM3/3/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org
On Tue, Mar 3, 2015 at 9:45 PM, Gabriel Dos Reis <g...@microsoft.com> wrote:
> Should we declare "auto f(auto) -> auto" an excess in sophism?

Truly we must - especially when discussing 'auto-nomy' ;)

Arthur O'Dwyer

unread,
Mar 4, 2015, 12:36:04 AM3/4/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com
On Tuesday, March 3, 2015 at 6:39:49 PM UTC-8, faisalv wrote:
In the hopes of soliciting constructive feedback, if anyone has the
time or the interest to play with a patched up Clang that implements
enhanced auto deduction & abbreviated template syntax from the
concepts ts, here it is:

https://github.com/faisalv/clang/tree/enhanced-auto-c%2B%2B1z .

That's very very cool — at least the "abbreviated template syntax" half! ;)  Is it possible for you to separate out the "abbreviated template syntax" feature from the "enhanced auto detection" feature, into two separate patches that could be looked at and/or adopted individually?
 
Now that we have generic lambdas (in C++14), I'm looking forward to having "generic functions" (i.e., abbreviated template syntax) sooner rather than later.

    // C++14: Create a lambda object with a template member operator()
   
auto f = [](auto x, auto y) { return x + y; };

   
// C++1z: Create a template function directly
   
auto f(auto x, auto y) { return x + y; }


1) Enhanced-Auto Deduction:

 pair<auto...> f() { return make_pair([] { }, [] { }); }
 vector<auto> v = vector<int>();

I don't see the use-case for this feature. Why would I write

    vector<auto> v = vector<int>();

when it's less typing and less noise to just write

    auto v = vector<int>();

? Also, as you noted in technicality (d), it's impossible to support "enhanced deduction" for type aliases. I don't like the asymmetry this creates between "class types" and "typedef types".  Here are a collection of "enhanced" cases where deduction fails (in some cases, MUST fail). 

    template<class T> using identity1 = T;
    identity1
<auto> id1 = 42;
   
template<class T> struct identity2 { using type = T; };
    identity2
<auto>::type id2 = 42;
   
template<class T> struct int3 { using type = int; };
    int3
<auto>::type id3 = 42;
   
template<class> using int4 = int;
    int4
<auto> id4 = 42;

I'm mostly concerned with the fact that you're making identity1<auto> fail, while vector<auto> succeeds.

Here's a use-case I could maybe get behind:

    vector<auto> vec = { 1, 2, 3 };  // creates a vector of int

except that (correct me if I'm wrong) your patch doesn't support that use-case. And I'm not sure how it could.


2) Abbreviated Template Syntax:
void f(auto) <=> template<class T> void f(T);

THIS is the very very awesome part. I am super excited about this feature finally coming to a compiler near me!

A few, perhaps not so obvious or interesting, technicalities:

a)  The equivalence of templates when it comes to trailing return
types in function pointer parameters is based on the order of the
'auto' that signifies a placeholder, not just the appearance of an
auto in the declaration-specifier of a parameter:

    template<class R, class P> void f( R(P) );  // #1
    template<class P, class R> void f(  R(P) );  // #2 (order of
templ-params flipped)

    template<class R, class P> void f( auto (P)->R); // equivalent to
#1, not abbreviated.

How many of these weirdnesses vanish if you get rid of "enhanced auto deduction"?
Clang 3.7.0 doesn't currently allow trailing return types on C++14 generic lambda parameters, which IMHO is a feature (in that allowing them leads to the grotesqueries you mention) but I'm pretty sure from the Standard's POV is a bug. (Contrariwise, I think GCC 5.0.0 is *too* permissive. But in neither case am I sure exactly what's allowed by the Standard.)

int one(int (*f)(int)) { return f(42); }  // C++03
int two(auto (*f)(int) -> int) { return f(42); }  // C++11
int three(auto (*f)(int)) { return f(42); }  // never
int four(auto (*f)(int) -> auto) { return f(42); }  // never
int five(int (*f)(auto)) { return f(42); }  // never
int six(int f(int)) { return f(42); }  // C++03 (takes a function pointer)
int seven(int f(auto)) { return f(42); }  // never


auto bone = [](int (*f)(int)) { return f(42); };  // C++11
auto btwo = [](auto (*f)(int) -> int) { return f(42); };  // never
auto bthree = [](auto (*f)(int)) { return f(42); };  // C++14
auto bfour = [](auto (*f)(int) -> auto) { return f(42); };  // never
auto bfive = [](int (*f)(auto)) { return f(42); };  // never
auto bsix = [](int f(int)) { return f(42); };  // C++11 (takes a function pointer)
auto bseven = [](int f(auto)) { return f(42); };  // never

 
    void f(auto(auto));  // equivalent to #1

IMHO, this should be disallowed. It deduces a function type for the parameter, and then "decays" that type to a function pointer, in the same way that parameters of array type "decay" to pointers. This was inherited from C, is super confusing, and in an age of generic lambda functors really deserves to be put to bed.

auto f(auto ga(auto)) { return ga("hello world"); }
auto g(auto xa) { puts(xa); }
int main() { f(g); }

Today, even though it looks like ga and g have the same type, they don't! g is a function template, and ga is a pointer to a function of unspecified type.
The idiomatically correct signature for f IMHO would be

    auto f(auto *ga) { return ga("hello world"); }


b) variadic auto
    Once an ellipsis is seen as part of the declarator, all contained
auto placeholders get transformed into parameter packs.
    void f(auto (*...)(auto) -> std::tuple<auto, std::pair<auto, auto>...>);
 Note there are 4 deducible template parameter packs above. 

Do I understand correctly that the above is exactly equivalent to

    template<class... A, class... B, class... C, class... D>
   
void f1(std::tuple<A, std::pair<B,C>...> (*...args)(D));

   
void f2(std::tuple<auto, std::pair<auto,auto>...> (*...args)(auto));

where f1 uses C++11 syntax and f2 uses only "abbreviated template" syntax?

c) multi abbreviated template declarations
   void f(auto), g(auto);
are allowed - the above declares two function templates.

That's not allowed for non-abbreviated templates, and again I don't see a use-case for it. What's a case where I would want to chain together function declarations like that? Again, that seems like cruft inherited from C that could easily be dumped at least for new syntax.
 
You don't mention this as a pitfall, but looking at your test cases I observed that

    auto foo = 42;  // foo is definitely an int
   
void bar(auto baz = 42);  // baz is NOT an int; it's of some deduced type.
                             
// The initializer 42 is coerced to that type if necessary.

Consider the following progression:

template<class X, class Y=int> auto one(X x, Y y=1) { return x+y; };  // legal C++14
template<class X, class Y> auto two(X x, Y y=1) { return x+y; };  // invalid, and rightly so
auto three = [](auto x, auto y=1) { return x+y; };  // invalid, but I claim it has an obvious meaning that should be standardized
auto four(auto x, auto y=1) { return x+y; };  // invalid?? with your patch, but I claim it has an obvious meaning
int main() { one(1); two(2); three(3); four(4); }

I know this has been a massive and scattered array of potshots, but I hope you find some of it interesting and/or useful. :)

–Arthur

Jonathan Wakely

unread,
Mar 4, 2015, 6:14:10 AM3/4/15
to c++std-core, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
On 4 March 2015 at 05:36, Arthur O'Dwyer wrote:
>>
>> 2) Abbreviated Template Syntax:
>> void f(auto) <=> template<class T> void f(T);
>
>
> THIS is the very very awesome part. I am super excited about this feature
> finally coming to a compiler near me!

Like GCC 4.9, released a year ago? :-)

https://gcc.gnu.org/gcc-4.9/changes.html#cxx

Faisal Vali

unread,
Mar 4, 2015, 7:45:04 AM3/4/15
to Arthur O'Dwyer, std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org
I generally agree with the above statement - but there are some who
have argued that it can improve readability - and I see their point
too.


> ? Also, as you noted in technicality (d), it's impossible to support
> "enhanced deduction" for type aliases. I don't like the asymmetry this
> creates between "class types" and "typedef types". Here are a collection of
> "enhanced" cases where deduction fails (in some cases, MUST fail).
>
> template<class T> using identity1 = T;
> identity1<auto> id1 = 42;
> template<class T> struct identity2 { using type = T; };
> identity2<auto>::type id2 = 42;
> template<class T> struct int3 { using type = int; };
> int3<auto>::type id3 = 42;
> template<class> using int4 = int;
> int4<auto> id4 = 42;
>
> I'm mostly concerned with the fact that you're making identity1<auto> fail,
> while vector<auto> succeeds.

Sorry, I was unclear - identity1<auto> id1 = 42 is the only one of
your examples that works. What does not work is: if you invent a
template parameter for each placeholder in your declaration - but
while doing template argument deduction thru a function call, if any
template parameters are left undeduced - that's an error (even if the
alias does not use the template parameter after desugarring).
Consider:
template<class T> void f(int4<T> id4);
f(42); // Error.


>
> Here's a use-case I could maybe get behind:
>
> vector<auto> vec = { 1, 2, 3 }; // creates a vector of int
>
> except that (correct me if I'm wrong) your patch doesn't support that
> use-case. And I'm not sure how it could.
>

No - since template argument deduction for function calls does not support that.

>>
>> 2) Abbreviated Template Syntax:
>> void f(auto) <=> template<class T> void f(T);
>
>
> THIS is the very very awesome part. I am super excited about this feature
> finally coming to a compiler near me!

Hah - our gcc friends have had this for ages :) - I've submitted a
patch for clang's review - but if history is any indication - the
review cycles (my latencies included) can take months.


>
>> A few, perhaps not so obvious or interesting, technicalities:
>>
>> a) The equivalence of templates when it comes to trailing return
>> types in function pointer parameters is based on the order of the
>> 'auto' that signifies a placeholder, not just the appearance of an
>> auto in the declaration-specifier of a parameter:
>>
>> template<class R, class P> void f( R(P) ); // #1
>> template<class P, class R> void f( R(P) ); // #2 (order of
>> templ-params flipped)
>>
>> template<class R, class P> void f( auto (P)->R); // equivalent to
>> #1, not abbreviated.
>
>
> How many of these weirdnesses vanish if you get rid of "enhanced auto
> deduction"?

None - this has nothing to do with initializer deduction - only
trailing return type syntax.

> Clang 3.7.0 doesn't currently allow trailing return types on C++14 generic
> lambda parameters, which IMHO is a feature (in that allowing them leads to
> the grotesqueries you mention) but I'm pretty sure from the Standard's POV
> is a bug. (Contrariwise, I think GCC 5.0.0 is *too* permissive. But in
> neither case am I sure exactly what's allowed by the Standard.)
>

No one is sure (except for maybe 10 or so kingsmen* that round table
it ~twice a year) exactly what's allowed by the standard ;)
(*) gender neutrality invoked

> http://melpon.org/wandbox/permlink/QMQXHNsBmwVJbxM0
> int one(int (*f)(int)) { return f(42); } // C++03
> int two(auto (*f)(int) -> int) { return f(42); } // C++11
> int three(auto (*f)(int)) { return f(42); } // never
> int four(auto (*f)(int) -> auto) { return f(42); } // never
> int five(int (*f)(auto)) { return f(42); } // never
> int six(int f(int)) { return f(42); } // C++03 (takes a function pointer)
> int seven(int f(auto)) { return f(42); } // never
>
>
> auto bone = [](int (*f)(int)) { return f(42); }; // C++11
> auto btwo = [](auto (*f)(int) -> int) { return f(42); }; // never
> auto bthree = [](auto (*f)(int)) { return f(42); }; // C++14
> auto bfour = [](auto (*f)(int) -> auto) { return f(42); }; // never
> auto bfive = [](int (*f)(auto)) { return f(42); }; // never
> auto bsix = [](int f(int)) { return f(42); }; // C++11 (takes a function
> pointer)
> auto bseven = [](int f(auto)) { return f(42); }; // never
>
>
>>
>> void f(auto(auto)); // equivalent to #1
>
>
> IMHO, this should be disallowed. It deduces a function type for the
> parameter, and then "decays" that type to a function pointer, in the same
> way that parameters of array type "decay" to pointers. This was inherited
> from C, is super confusing, and in an age of generic lambda functors really
> deserves to be put to bed.

I hear you - but it is easier to write test cases without the extra
syntax to denote a ptr or ref.

>
> auto f(auto ga(auto)) { return ga("hello world"); }
> auto g(auto xa) { puts(xa); }
> int main() { f(g); }
>
> Today, even though it looks like ga and g have the same type, they don't! g
> is a function template, and ga is a pointer to a function of unspecified
> type.
> The idiomatically correct signature for f IMHO would be
>
> auto f(auto *ga) { return ga("hello world"); }
>
>
>> b) variadic auto
>> Once an ellipsis is seen as part of the declarator, all contained
>> auto placeholders get transformed into parameter packs.
>> void f(auto (*...)(auto) -> std::tuple<auto, std::pair<auto,
>> auto>...>);
>> Note there are 4 deducible template parameter packs above.
>
>
> Do I understand correctly that the above is exactly equivalent to
>
> template<class... A, class... B, class... C, class... D>
> void f1(std::tuple<A, std::pair<B,C>...> (*...args)(D));
>
> void f2(std::tuple<auto, std::pair<auto,auto>...> (*...args)(auto));
>
> where f1 uses C++11 syntax and f2 uses only "abbreviated template" syntax?
>

Yes.


>> c) multi abbreviated template declarations
>> void f(auto), g(auto);
>> are allowed - the above declares two function templates.
>
>
> That's not allowed for non-abbreviated templates, and again I don't see a
> use-case for it. What's a case where I would want to chain together function
> declarations like that? Again, that seems like cruft inherited from C that
> could easily be dumped at least for new syntax.
>

I don't think I care much either way - but I don't think this
forbidden by the TS.

> You don't mention this as a pitfall, but looking at your test cases I
> observed that
>
> auto foo = 42; // foo is definitely an int
> void bar(auto baz = 42); // baz is NOT an int; it's of some deduced
> type.
> // The initializer 42 is coerced to that type
> if necessary.

Yes - I can see the potential for confusion - but perhaps if you
mentally replace an 'auto' in a function declaration with a template
type parameter, and in an initializer deduction with a function call
with the initializer, perhaps the confusion can be minimized - but I
agree, it is unfortunate that such asymmetry exists.

>
> Consider the following progression:
>
> template<class X, class Y=int> auto one(X x, Y y=1) { return x+y; }; //
> legal C++14
> template<class X, class Y> auto two(X x, Y y=1) { return x+y; }; //
> invalid, and rightly so
> auto three = [](auto x, auto y=1) { return x+y; }; // invalid, but I claim
> it has an obvious meaning that should be standardized
> auto four(auto x, auto y=1) { return x+y; }; // invalid?? with your patch,
> but I claim it has an obvious meaning
> int main() { one(1); two(2); three(3); four(4); }
>
> I know this has been a massive and scattered array of potshots, but I hope
> you find some of it interesting and/or useful. :)
>
> –Arthur

I certainly did - Thanks!

Ville Voutilainen

unread,
Mar 4, 2015, 7:49:03 AM3/4/15
to std-pr...@isocpp.org, Arthur O'Dwyer, std-dis...@isocpp.org, c++st...@accu.org
On 4 March 2015 at 14:45, Faisal Vali <fai...@gmail.com> wrote:
>> I don't see the use-case for this feature. Why would I write
>>
>> vector<auto> v = vector<int>();
>>
>> when it's less typing and less noise to just write
>>
>> auto v = vector<int>();
>>
> I generally agree with the above statement - but there are some who
> have argued that it can improve readability - and I see their point
> too.

That's a bad example for it. A better one is
vector<auto> v = some_function();
where you don't care about the exact return type of some_function,
but you do want to ensure it's a vector. Such ensuring is indeed completely
unnecessary for the example above where the type created is visible
in a crystal clear fashion.

Klaim - Joël Lamotte

unread,
Mar 4, 2015, 7:50:33 AM3/4/15
to std-dis...@isocpp.org, Arthur O'Dwyer, std-pr...@isocpp.org, c++st...@accu.org

On Wed, Mar 4, 2015 at 1:45 PM, Faisal Vali <fai...@gmail.com> wrote:
> I don't see the use-case for this feature. Why would I write
>
>     vector<auto> v = vector<int>();
>
> when it's less typing and less noise to just write
>
>     auto v = vector<int>();
>

I generally agree with the above statement - but there are some who
have argued that it can improve readability - and I see their point
too.

Another argument would be that if you have

    auto v = generateData();

It is less constrained than

    vector<auto> v = generateData();

which add an interesting constraint that generateData() must return a vector, not just something that
have the same interface.
It looks like improved granularity on constraints specifications.

Bjarne Stroustrup

unread,
Mar 4, 2015, 11:14:45 AM3/4/15
to c++st...@accu.org, std-pr...@isocpp.org, Arthur O'Dwyer, std-dis...@isocpp.org
and then, with suitable concepts and a much-asked-for extension of
concepts to allow placement of concepts roughly wherever "auto" can be
placed:

Container v = some_function();

and

vector<Some_string_type> v = some_function();

Bjarne Stroustrup

unread,
Mar 4, 2015, 11:17:23 AM3/4/15
to c++st...@accu.org, <std-proposals@isocpp.org>, std-dis...@isocpp.org


On 3/3/2015 10:45 PM, Gabriel Dos Reis wrote:
> Should we declare "auto f(auto) -> auto" an excess in sophism?


and those two "auto"s can denote different and unrelated types?

Faisal Vali

unread,
Mar 4, 2015, 11:40:59 AM3/4/15
to std-dis...@isocpp.org, c++st...@accu.org, <std-proposals@isocpp.org>
On Wed, Mar 4, 2015 at 10:17 AM, Bjarne Stroustrup
<bja...@stroustrup.com> wrote:
>
>
> On 3/3/2015 10:45 PM, Gabriel Dos Reis wrote:
>>
>> Should we declare "auto f(auto) -> auto" an excess in sophism?
>
>
>
> and those two "auto"s can denote different and unrelated types?
>

yes - the first 'auto' is a trailing return type signifier, the second
'auto' is an abbreviated template signifier (adds a template parameter
to the function template's template parameter list) and is deduced
from the supplied argument, the third auto is the placeholder for
return type deduction and is deduced from a return statement within
the body of the function - it does not add a template parameter to
the function template's template parameter list - and is quite
different from the second auto in that way.
> Groups "ISO C++ Standard - Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-discussio...@isocpp.org.
> To post to this group, send email to std-dis...@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-discussion/.

Scott Prager

unread,
Mar 4, 2015, 11:52:51 AM3/4/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com
Great stuff! No more writing is_tuple and is_pair functions to get
SFINAE overloading. Although, a few things get me...

(sorry, the code formatter isn't working for me right now)

/// TEST
template<class X>
void check(auto&& x) {
static_assert(std::is_same<decltype(x), X&&>::value);
}

template<class X>
void check_copy(auto x) {
static_assert(std::is_same<decltype(x), X>::value);
}

//...

int one;
const int cone = 1;
check<int>(1);
check<int&>(one);
check<const int&>(cone);

check_copy<int>(1);
check_copy<int>(one);
check_copy<int>(cone);
/// END TEST

So, this check shows that when used as a function parameter,
auto behaves very similarly to auto-initializing a variable.

/// TEST
std::pair<auto...> p = std::pair<int, int>(1,1);
std::pair<auto...> q = std::pair<int&, int&>(one,one);
std::pair<auto...> r = std::pair<int&&, int&&>(1,1);

template<class X> using P = std::pair<X,X>&;
check<P<int>>(p);
check<P<int&>>(q);
check<P<int&&>>(r);
/// END TEST

This should that auto as a template parameter works consistently in
that tuple<T> would bind to a reference or rvlaue as well. I tested
auto& and auto&& in this context as well, and they match against
references and rvalues like template parameters.

void check_pair(std::pair<auto&&, auto&&>) { static_assert(true); }

Particularly, this will only work if passed a pair<X&&, Y&&> with std::move...
While it's entirely consistent with the rest of the language, it just
seems odd that auto in one instance decays the type and in another
acts like decltype(auto). Not a complaint, just an observation.

Gabriel Dos Reis

unread,
Mar 4, 2015, 11:55:55 AM3/4/15
to <std-discussion@isocpp.org>, c++st...@accu.org, <std-proposals@isocpp.org>
But the "late return type" signifier was there only because we could not get the natural and simpler syntax in C++11!

I am hoping we are not retaining complexity only because we can.

"auto" is the new "static".

-- Gaby

Matthew Fioravante

unread,
Mar 4, 2015, 12:14:13 PM3/4/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com


On Wednesday, March 4, 2015 at 12:36:02 AM UTC-5, Arthur O'Dwyer wrote:

I don't see the use-case for this feature. Why would I write

    vector<auto> v = vector<int>();

when it's less typing and less noise to just write

    auto v = vector<int>();

The use case for this:

vector<int> v;

array_view<auto> av = v; //deduces to array_view<int>



Tony Van Eerd

unread,
Mar 4, 2015, 12:15:09 PM3/4/15
to c++st...@accu.org, std-pr...@isocpp.org, Arthur O'Dwyer, std-dis...@isocpp.org
> From: Bjarne Stroustrup [mailto:bja...@stroustrup.com]
>
> and then, with suitable concepts and a much-asked-for extension of
> concepts to allow placement of concepts roughly wherever "auto" can be
> placed:
>
> Container v = some_function();
>

Yes please.

To me, auto has the same problems as templates without concepts.
Tony

Faisal Vali

unread,
Mar 4, 2015, 12:28:47 PM3/4/15
to Arthur O'Dwyer, <std-proposals@isocpp.org>, std-dis...@isocpp.org, c++st...@accu.org
On Wed, Mar 4, 2015 at 6:45 AM, Faisal Vali <fai...@gmail.com> wrote:
> On Tue, Mar 3, 2015 at 11:36 PM, Arthur O'Dwyer
> <arthur....@gmail.com> wrote:
>> On Tuesday, March 3, 2015 at 6:39:49 PM UTC-8, faisalv wrote:
>>>
<snip>
>>
>>> b) variadic auto
>>> Once an ellipsis is seen as part of the declarator, all contained
>>> auto placeholders get transformed into parameter packs.
>>> void f(auto (*...)(auto) -> std::tuple<auto, std::pair<auto,
>>> auto>...>);
>>> Note there are 4 deducible template parameter packs above.
>>
>>
>> Do I understand correctly that the above is exactly equivalent to
>>
>> template<class... A, class... B, class... C, class... D>
>> void f1(std::tuple<A, std::pair<B,C>...> (*...args)(D));
>>
>> void f2(std::tuple<auto, std::pair<auto,auto>...> (*...args)(auto));
>>
>> where f1 uses C++11 syntax and f2 uses only "abbreviated template" syntax?
>>
>
> Yes.
>
Hmm - just a minor technicality, but actually, they are not all
redeclarations of the same template, the two that you wrote are
equivalent to each other, but the first one is equivalent to the
following (note the order of the template parameters)
template<class ... A, class ... B, class... C, class...D>
void f(tuple<B, pair<C,D>...)(*...)(A));

in case anyone cares ...

Bjarne Stroustrup

unread,
Mar 4, 2015, 12:55:20 PM3/4/15
to c++st...@accu.org, std-pr...@isocpp.org, Arthur O'Dwyer, std-dis...@isocpp.org
Exactly

Geoffrey Romer

unread,
Mar 4, 2015, 12:59:46 PM3/4/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
On Tue, Mar 3, 2015 at 9:36 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
On Tuesday, March 3, 2015 at 6:39:49 PM UTC-8, faisalv wrote:
In the hopes of soliciting constructive feedback, if anyone has the
time or the interest to play with a patched up Clang that implements
enhanced auto deduction & abbreviated template syntax from the
concepts ts, here it is:

https://github.com/faisalv/clang/tree/enhanced-auto-c%2B%2B1z .

That's very very cool — at least the "abbreviated template syntax" half! ;)

Interesting; my reaction is precisely the opposite- I find enhanced auto deduction very appealing (for reasons that others on this thread have elaborated), but am actively uninterested in the abbreviated template syntax. It seems to me to offer only a modest improvement in brevity, and pays for it with a very substantial reduction in readability. That compromise may be appropriate for lambdas, because brevity is particularly important inside a single expression, but it seems far less justifiable in the case of ordinary functions. Functions are not under the kinds of space constraints that lambdas are, and function signatures (unlike lambda signatures) often act as abstraction boundaries, so it's particularly important for them to convey useful information to the reader.

Jonathan Wakely

unread,
Mar 5, 2015, 6:24:05 AM3/5/15
to c++std-core, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
On 4 March 2015 at 17:59, Geoffrey Romer wrote:
> Interesting; my reaction is precisely the opposite- I find enhanced auto
> deduction very appealing (for reasons that others on this thread have
> elaborated), but am actively uninterested in the abbreviated template
> syntax. It seems to me to offer only a modest improvement in brevity, and
> pays for it with a very substantial reduction in readability. That
> compromise may be appropriate for lambdas, because brevity is particularly
> important inside a single expression, but it seems far less justifiable in
> the case of ordinary functions. Functions are not under the kinds of space
> constraints that lambdas are, and function signatures (unlike lambda
> signatures) often act as abstraction boundaries, so it's particularly
> important for them to convey useful information to the reader.

This conveys useful information:

template<typename ForwardIterator>
ForwardIterator next(ForwardIterator);

but that's still true if it's rewritten like this:

ForwardIterator next(ForwardIterator);

This doesn't convey any useful information:

template<typename T>
void frob(T);

so in terms of describing the interface it's no different when written
like this:

void frob(auto);

Geoffrey Romer

unread,
Mar 5, 2015, 12:12:00 PM3/5/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
On Thu, Mar 5, 2015 at 3:23 AM, Jonathan Wakely <c...@kayari.org> wrote:
On 4 March 2015 at 17:59, Geoffrey Romer wrote:
> Interesting; my reaction is precisely the opposite- I find enhanced auto
> deduction very appealing (for reasons that others on this thread have
> elaborated), but am actively uninterested in the abbreviated template
> syntax. It seems to me to offer only a modest improvement in brevity, and
> pays for it with a very substantial reduction in readability. That
> compromise may be appropriate for lambdas, because brevity is particularly
> important inside a single expression, but it seems far less justifiable in
> the case of ordinary functions. Functions are not under the kinds of space
> constraints that lambdas are, and function signatures (unlike lambda
> signatures) often act as abstraction boundaries, so it's particularly
> important for them to convey useful information to the reader.

This conveys useful information:

template<typename ForwardIterator>
  ForwardIterator next(ForwardIterator);

but that's still true if it's rewritten like this:

ForwardIterator next(ForwardIterator);

That's not what I'm objecting to; I'm objecting to "auto" specifically. But since you mention it, this version definitely conveys less information than the previous one: it obscures the critical fact that 'next' is a function template.
 

This doesn't convey any useful information:

template<typename T>
  void frob(T);

I don't agree; it tells me that frob is a generic operation that works with roughly any type T.
 

so in terms of describing the interface it's no different when written
like this:

void frob(auto);

This is different because now I don't know anything about the requirements or semantics of the parameter type. Even if a conceptified version of this syntax is available, "auto" doesn't necessarily tell me that the operation is generic; it may just mean that there's no named concept that captures the meaning of the parameter.

Nevin Liber

unread,
Mar 5, 2015, 12:26:00 PM3/5/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, Faisal Vali
On 5 March 2015 at 11:11, 'Geoffrey Romer' via ISO C++ Standard - Future Proposals <std-pr...@isocpp.org> wrote:

This doesn't convey any useful information:

template<typename T>
  void frob(T);

I don't agree; it tells me that frob is a generic operation that works with roughly any type T.

But what does that mean?  Sure, I can copy/move it (since it was passed by value), but any other constraints will be dictated by the body of frob.
 
 
so in terms of describing the interface it's no different when written
like this:

void frob(auto);

This is different because now I don't know anything about the requirements or semantics of the parameter type.

I'm just not seeing how that is any different (other than the incredibly minor of having to call decltype on its parameter to get its type).

Do you have an example function body that works with frob(T) but doesn't work with frob(auto) (or vice versa) for a specific concrete type?  I'm really trying to understand the difference you see between these two forms.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Geoffrey Romer

unread,
Mar 5, 2015, 1:10:46 PM3/5/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali
On Thu, Mar 5, 2015 at 9:25 AM, Nevin Liber <ne...@eviloverlord.com> wrote:
On 5 March 2015 at 11:11, 'Geoffrey Romer' via ISO C++ Standard - Future Proposals <std-pr...@isocpp.org> wrote:

This doesn't convey any useful information:

template<typename T>
  void frob(T);

I don't agree; it tells me that frob is a generic operation that works with roughly any type T.

But what does that mean?  Sure, I can copy/move it (since it was passed by value), but any other constraints will be dictated by the body of frob.

My point is that the use of a generic, meaningless parameter name like "T" tacitly documents the fact that frob isn't going to dictate many additional constraints, beyond perhaps highly generic ones like being able to compare for equality.
 
 
 
so in terms of describing the interface it's no different when written
like this:

void frob(auto);

This is different because now I don't know anything about the requirements or semantics of the parameter type.

I'm just not seeing how that is any different (other than the incredibly minor of having to call decltype on its parameter to get its type).

Do you have an example function body that works with frob(T) but doesn't work with frob(auto) (or vice versa) for a specific concrete type?  I'm really trying to understand the difference you see between these two forms.

I'm not aware of any code that will work with one form but not the other. My point is simply that "auto" conveys less information to me as a human reader than a named template parameter would.

Zhihao Yuan

unread,
Mar 5, 2015, 1:58:06 PM3/5/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, fai...@gmail.com
On Wed, Mar 4, 2015 at 12:59 PM, 'Geoffrey Romer' via ISO C++ Standard
- Future Proposals <std-pr...@isocpp.org> wrote:
>
> I find enhanced auto
> deduction very appealing (for reasons that others on this thread have
> elaborated), but am actively uninterested in the abbreviated template
> syntax. It seems to me to offer only a modest improvement in brevity, and
> pays for it with a very substantial reduction in readability. That
> compromise may be appropriate for lambdas, because brevity is particularly
> important inside a single expression, but it seems far less justifiable in
> the case of ordinary functions.

I objected the use of `auto` in generic lambda.

But for now, for "consistency", I think the connection
between

auto f(auto, auto) { ... }

and

auto f = [](auto, auto) { ... }

is desired.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://bit.ly/blog4bsd

Ville Voutilainen

unread,
Mar 5, 2015, 2:09:56 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali
Dropping Core, this is not a Core discussion.

On 5 March 2015 at 20:10, 'Geoffrey Romer' via ISO C++ Standard -
Future Proposals <std-pr...@isocpp.org> wrote:
> My point is that the use of a generic, meaningless parameter name like "T"
> tacitly documents the fact that frob isn't going to dictate many additional
> constraints, beyond perhaps highly generic ones like being able to compare
> for equality.

void frob(auto); seemingly conveys the same information, once you get
used to it.
It also happens to be a nicely terse way to not write the
template-header boilerplate
for cases where you don't use that boilerplate for anything.

>> Do you have an example function body that works with frob(T) but doesn't
>> work with frob(auto) (or vice versa) for a specific concrete type? I'm
>> really trying to understand the difference you see between these two forms.
> I'm not aware of any code that will work with one form but not the other. My
> point is simply that "auto" conveys less information to me as a human reader
> than a named template parameter would.

In
template <class T> void frob(T t)
{
// I can use T here for various purposes
}
and in
void frob(auto t)
{
// if I want to use 'T' here, I need to do a decltype(t) to get at it
}

Tom Honermann

unread,
Mar 5, 2015, 3:28:18 PM3/5/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, Faisal Vali
On 03/05/2015 01:10 PM, 'Geoffrey Romer' via ISO C++ Standard - Future
> I'm not aware of any code that will work with one form but not the
> other. My point is simply that "auto" conveys less information to me as
> a human reader than a named template parameter would.

I've felt concerns about this as well, specifically with respect to
behavioral differences observable in template functions vs non-template
functions.

We all know that there is one object with static storage duration
defined by this function:
void f(int i) {
static int invoke_count;
++invoke_count;
}

And we all know that there are potentially many objects with static
storage duration defined by this template function, one for each
instantiation:
template<typename T>
void f(int i) {
static int invoke_count;
++invoke_count;
}

But, it is less apparent how many objects with static storage duration
are defined by this function:
void f(auto t) {
static int invoke_count;
++invoke_count;
}

I don't know that this is a significant concern. But it is enough to
give me pause. I've personally never minded the template boilerplate,
but I guess I'm weird that way.

Tom.

Geoffrey Romer

unread,
Mar 5, 2015, 5:37:43 PM3/5/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali
Another one: which of these definitions can safely be in a header file?
 
  I've personally never minded the template boilerplate, but I guess I'm weird that way.

Me neither, and in fact I don't see the template header as "boilerplate" at all. The only template boilerplate I mind is having to spell out

template <typename T, typename U, typename V>
MyClassName<T,U,V>::
 
over and over for every method I define outside the class body, but I don't think abbreviated template syntax helps with that.

Thiago Macieira

unread,
Mar 5, 2015, 5:41:07 PM3/5/15
to std-dis...@isocpp.org
On Thursday 05 March 2015 15:28:09 Tom Honermann wrote:
> I don't know that this is a significant concern. But it is enough to
> give me pause. I've personally never minded the template boilerplate,
> but I guess I'm weird that way.

I'm with Tom here that the lack of "template" anywhere could lead people to
forget that the function is actually a template. I don't see this as a problem
for "auto", but it might be for concepts:

void f(Container t) {
static int invoke_count;
++invoke_count;
}

Is that a template or not? I need to look up the definition of Container to
figure out whether it's a concept or a regular class.

I wouldn't mind if we required the "template" keyword to appear in the
declaration of functions using concepts.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Nicol Bolas

unread,
Mar 5, 2015, 6:19:19 PM3/5/15
to std-dis...@isocpp.org, std-pr...@isocpp.org, c++st...@accu.org, fai...@gmail.com
I... just... ugh.

I'm fine with type deduction patterns like std::vector<auto> = ...; That's just a generalization of type deduction in static contexts.

My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets. Templates are a fundamentally different kind of construct, and we have specific syntax for doing so. By removing that syntax, it becomes way too easy to not notice that you've declared a template.

The last thing we should want is for people to accidentally make something a template.

I accept this with lambdas, because the main point of lambdas is that they're a short-cut. Furthermore, they have a syntax that's fundamentally different from regular functions. But for a regular function? No.

Basically, if I see this:

X func_name(...);

I expect that &func_name ought to return a pointer. For it to do something else, like being a compiler error, would be surprising.

Ville Voutilainen

unread,
Mar 5, 2015, 6:36:21 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali
On 6 March 2015 at 01:19, Nicol Bolas <jmck...@gmail.com> wrote:
> My issue is with, well, any syntax that declares a template without having
> to type either the word "template" or the use of "<>" brackets. Templates
> are a fundamentally different kind of construct, and we have specific syntax
> for doing so. By removing that syntax, it becomes way too easy to not notice
> that you've declared a template.

Why is that a problem?

> The last thing we should want is for people to accidentally make something a
> template.

Same question.

> I accept this with lambdas, because the main point of lambdas is that
> they're a short-cut. Furthermore, they have a syntax that's fundamentally
> different from regular functions. But for a regular function? No.

Ditto.

>
> Basically, if I see this:
>
> X func_name(...);
>
> I expect that &func_name ought to return a pointer. For it to do something
> else, like being a compiler error, would be surprising.

That already happens if func_name is overloaded, so the terse template
declaration
syntax doesn't introduce that particular problem.

Matthew Fioravante

unread,
Mar 5, 2015, 6:43:16 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com


On Thursday, March 5, 2015 at 2:09:56 PM UTC-5, Ville Voutilainen wrote:

void frob(auto t)
{
    // if I want to use 'T' here, I need to do a decltype(t) to get at it
}

You may need remove pointer, ref, and/or cv qualifiers if you use auto*, auto&& (perfect forwarding), const auto&, etc.. using type_traits. If the signature changes, you'll have to remember to fix the traits you used. 

If your implementation needs to express type T, it might be better to use the old template syntax.

Matthew Fioravante

unread,
Mar 5, 2015, 6:46:23 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com


On Thursday, March 5, 2015 at 6:19:20 PM UTC-5, Nicol Bolas wrote:
I... just... ugh.

I'm fine with type deduction patterns like std::vector<auto> = ...; That's just a generalization of type deduction in static contexts.

My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets. Templates are a fundamentally different kind of construct, and we have specific syntax for doing so. By removing that syntax, it becomes way too easy to not notice that you've declared a template.

You could add a requirement for an empty template <> when using auto.

template <>
auto add(auto x, auto y) { return x + y; }

Ville Voutilainen

unread,
Mar 5, 2015, 6:52:40 PM3/5/15
to std-dis...@isocpp.org, std-pr...@isocpp.org, Faisal Vali
On 6 March 2015 at 01:43, Matthew Fioravante <fmatth...@gmail.com> wrote:
>> void frob(auto t)
>> {
>> // if I want to use 'T' here, I need to do a decltype(t) to get at it
>> }
> You may need remove pointer, ref, and/or cv qualifiers if you use auto*,
> auto&& (perfect forwarding), const auto&, etc.. using type_traits. If the
> signature changes, you'll have to remember to fix the traits you used.

Yes. Not that the "signature changes" is all that much different from an
old-skool template.

> If your implementation needs to express type T, it might be better to use
> the old template syntax.

Perhaps so. That may be a fairly big "if".

Klaim - Joël Lamotte

unread,
Mar 5, 2015, 6:53:57 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com

​I don't see the point in adding such requirement for people who don't consider it a problem
(me included). My understanding is that the proposal provide several ways to say aproximatively
the same thing and you can easily chose the level of details that suits your viewpoint.
I think it's better that way.

Richard Smith

unread,
Mar 5, 2015, 7:12:21 PM3/5/15
to std-dis...@isocpp.org, std-pr...@isocpp.org, c++st...@accu.org, Faisal Vali
... except that "template <>" currently always introduces a non-template, and generally follows non-template rules (can be defined outside of the header, etc). I don't think that solves the problem.

Herb Sutter

unread,
Mar 5, 2015, 7:24:32 PM3/5/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com

To paraphrase Stroustrup, it’s not about functional programming and object-oriented programming and generic programming… “it’s all just programming.”

 

> Templates are a fundamentally different kind of construct

 

Why? Every full specialization of a function template is just a function.

 

> My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets.

 

That ship has sailed:

 

                auto plus = [](auto x, auto y) { return x+y; }

 

which even already decays to an ordinary pointer to function, etc.

 

Clarifying Q: Are we mainly arguing about whether to require the three characters =, [, and ] ?

 

Not only has the ship sailed, but I for one like the direction it’s sailing. I see no reason why functions should be forced to spell “template” and “<>”. What value does it add? It’s “just programming.” In fact, if we didn’t have backward compatibility issues with unnamed parameters and such, I’d personally probably be fine with just “auto plus(x,y){x+y}” as an equivalent function definition. That still doesn’t lose any information.

 

Gratuitous syntax is often unnecessary and usually harmful. Saying

 

                template<class T, class U>

                auto(T x, U y) -> decltype(x+y) { return x+y; }

 

does not appear to me to contain any more information than

 

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

 

does it? Requiring the verbose syntax is gratuitous, if the verbose syntax does not add information, does not serve to disambiguate anything, and does not highlight a dangerous operation or anything else I can see that deserves to have attention called to it.

 

There’s a disturbing (to me and at least some others) trend in C++ these days: People seem to be very prone to wanting “more syntax” lately. It’s rather Vasa-like, if only lexically. Let me channel certain influential committee members and say: ‘People these days are always asking for more syntax! There’s no proposal they’ve seen that they couldn’t make uglier with more syntax!’

 

Important note: The point here is NOT terseness for terseness’ sake. I am not arguing that terser is somehow better, that terseness is virtuous in itself. Too many people glorify languages because they’re terser; fewer characters alone doesn’t make code clearer. Rather, my point is to avoid gratuitous verbosity. At the other end of the pendulum, too many people glorify verbose syntax because they think _that_ is somehow inherently clearer; usually it isn’t. So I am arguing that neither is verbosity virtuous in itself.

 

Herb

Richard Smith

unread,
Mar 5, 2015, 8:01:26 PM3/5/15
to c++std-core, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
On 5 March 2015 at 16:24, Herb Sutter <hsu...@microsoft.com> wrote:

To paraphrase Stroustrup, it’s not about functional programming and object-oriented programming and generic programming… “it’s all just programming.”

 

> Templates are a fundamentally different kind of construct

 

Why? Every full specialization of a function template is just a function.

 

> My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets.

 

That ship has sailed:

 

                auto plus = [](auto x, auto y) { return x+y; }

 

which even already decays to an ordinary pointer to function, etc.

 

Clarifying Q: Are we mainly arguing about whether to require the three characters =, [, and ] ?

 

Not only has the ship sailed, but I for one like the direction it’s sailing. I see no reason why functions should be forced to spell “template” and “<>”. What value does it add? It’s “just programming.” In fact, if we didn’t have backward compatibility issues with unnamed parameters and such, I’d personally probably be fine with just “auto plus(x,y){x+y}” as an equivalent function definition. That still doesn’t lose any information.

 

Gratuitous syntax is often unnecessary and usually harmful. Saying

 

                template<class T, class U>

                auto(T x, U y) -> decltype(x+y) { return x+y; }

 

does not appear to me to contain any more information than

 

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

 

does it?


To me, yes, it does. It says:

 * I deliberately want to allow the parameters to have different types
 * I deliberately want to allow the return type to differ from those types
 * I want a substitution failure if x + y is not valid (your rewrite is possibly incorrect due to this)
 * I want to "perfectly return" x + y rather than always returning by value (your rewrite is possibly incorrect due to this)
 * It's OK for this apparent function definition to be in a header file despite not including the 'inline' keyword
 * It's *not* OK to move this definition out of the header file.
 * And the big one: it says "this is a template". No need to go scanning the declaration for "auto" (or for concept names, not that you can identify them by sight). It's right there at the start.

It's somewhat less clear to me how this loss of readability balances against the possibility of improved readability from a shorter declaration.

Requiring the verbose syntax is gratuitous, if the verbose syntax does not add information, does not serve to disambiguate anything, and does not highlight a dangerous operation or anything else I can see that deserves to have attention called to it.

 

There’s a disturbing (to me and at least some others) trend in C++ these days: People seem to be very prone to wanting “more syntax” lately. It’s rather Vasa-like, if only lexically. Let me channel certain influential committee members and say: ‘People these days are always asking for more syntax! There’s no proposal they’ve seen that they couldn’t make uglier with more syntax!’

 

Important note: The point here is NOT terseness for terseness’ sake. I am not arguing that terser is somehow better, that terseness is virtuous in itself. Too many people glorify languages because they’re terser; fewer characters alone doesn’t make code clearer. Rather, my point is to avoid gratuitous verbosity. At the other end of the pendulum, too many people glorify verbose syntax because they think _that_ is somehow inherently clearer; usually it isn’t. So I am arguing that neither is verbosity virtuous in itself.


Right; we need to find a balance where the syntax we have is neither unnecessarily terse (to the point of causing readability and maintenance problems) nor unnecessarily verbose. It is up to the people proposing the change to demonstrate that this requirement is met, and the reactions on this thread seem to suggest that we are, so far, lacking a good argument that the proposed syntax meets the Goldilocks criterion.

Thiago Macieira

unread,
Mar 5, 2015, 8:03:42 PM3/5/15
to std-dis...@isocpp.org, Faisal Vali, std-pr...@isocpp.org
On Tuesday 03 March 2015 20:39:47 Faisal Vali wrote:
> 1) Enhanced-Auto Deduction:
>
> pair<auto...> f() { return make_pair([] { }, [] { }); }
> vector<auto> v = vector<int>();

What's the value of this syntax? Is it only to make it a compiler error if the
RHS isn't the type I had on the left?

That is, is it to make the following a compilation error:

std::vector<auto> v = someFunction();

if someFunction() returned QVector<int> instead of std::vector<int>?

Or is this syntax going to deduce the template parameters for the LHS from the
template parameters from the RHS, then convert? In other words, is the
following meant to be allowed?

template <typename T> struct S1 {};
template <typename T> struct S2
{
S2() = default;
S2(X<T>) {}
};

S1<int> someFunction();

...
S2<auto> v = someFunction();
// v is S2<int>

If that is the case, what are the rules for when the RHS has more template
parameters than the LHS? Just silently drop? (example: converting from
std::vector<T, Allocator> to QVector<T>).

And if the LHS has more parameters but those have default values, will it also
be allowed (from QVector<T> to std::vector<T, Allocator = allocator<T>>)?

Richard Smith

unread,
Mar 5, 2015, 8:08:18 PM3/5/15
to std-dis...@isocpp.org, Faisal Vali, c++st...@accu.org, std-pr...@isocpp.org

Incidentally, this is one thing I love about the concepts TS: it lets us form a much stronger argument about the merits here based on actual user experience.

>> Herb
>>
>>  
>>
>>  
>>
>> From: Nicol Bolas [mailto:jmck...@gmail.com]
>> Sent: Thursday, March 5, 2015 3:19 PM
>> To: std-dis...@isocpp.org
>> Cc: std-pr...@isocpp.org; c++st...@accu.org; fai...@gmail.com
>> Subject: [c++std-core-27204] Re: An implementation of enhanced auto deduction and abbreviated template syntax using Clang
>>
>>  
>>
>> I... just... ugh.
>>
>> I'm fine with type deduction patterns like std::vector<auto> = ...; That's just a generalization of type deduction in static contexts.
>>
>> My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets. Templates are a fundamentally different kind of construct, and we have specific syntax for doing so. By removing that syntax, it becomes way too easy to not notice that you've declared a template.
>>
>> The last thing we should want is for people to accidentally make something a template.
>>
>> I accept this with lambdas, because the main point of lambdas is that they're a short-cut. Furthermore, they have a syntax that's fundamentally different from regular functions. But for a regular function? No.
>>
>> Basically, if I see this:
>>
>> X func_name(...);
>>
>> I expect that &func_name ought to return a pointer. For it to do something else, like being a compiler error, would be surprising.
>
>

Scott Prager

unread,
Mar 5, 2015, 8:22:10 PM3/5/15
to std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
I can see where a lot of discomfort might come, here... 

(1) Just plain auto seems imprecise and it makes template functions look like
non-template functions.

(2) Named template parameters seem to provide comparatively more information.

For (1), this seems like a special case. When you consider inlining, changing
functions that take reference parameters of basic types to pass by value, and
other such optimizations our compilers perform, functions have never really
been the concrete entities we like to think of them as. I don't see a need to
distinguish between template and non-template functions from a user
point-of-view, except when using extern "C".

(2): As mentioned, one can always fall back on normal template syntax, but
also, I don't know about anyone else, but I tend to name my types verbosely,
and my variables tersely. So I'll write...

template<class Sequence, class UnaryFunction>
void for_each(Sequence& seq, UnaryFunction f) { for(auto&& x : seq) f(x); }


...but with auto as the parameter type, I would reverse this trend:

void for_each(auto& sequence, auto unary_op) { for(auto&& x : sequence) unary_op(x); }

...and I think that reads better.

Another reason I think we should embrace this: It brings template code within
reach of absolute beginners, both to C++ and programming in general. Trying to
teach an initiate what this means...

template<typename Function, typename Value>
auto f(Function fn, Value v) { return fn(v); }

requires teaching the meaning on "typename" (because the user may not have
needed typedefs or type aliases at this point), template<...>, how "Function"
and "Value" do not denote real types, etc., etc.. But explaining this...

auto f(auto fn, auto val) { return fn(val); }

...well, they probably already are familiar with auto, using auto as a
parameter is intuitive, and those familiar with dynamic languages will feel
right at home, while benefiting from static typing.

Scott Prager

unread,
Mar 5, 2015, 8:30:55 PM3/5/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, richar...@google.com


On Thursday, March 5, 2015 at 8:01:26 PM UTC-5, Richard Smith wrote:
On 5 March 2015 at 16:24, Herb Sutter <hsu...@microsoft.com> wrote:

 

Gratuitous syntax is often unnecessary and usually harmful. Saying

 

                template<class T, class U>

                auto(T x, U y) -> decltype(x+y) { return x+y; }

 

does not appear to me to contain any more information than

 

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

 

does it?


To me, yes, it does. It says:

 * I deliberately want to allow the parameters to have different types
 * I deliberately want to allow the return type to differ from those types

Does that mean that the version using auto accidentally allows the arguments to have different types, and return a different type?
 
 * I want a substitution failure if x + y is not valid (your rewrite is possibly incorrect due to this)
 * I want to "perfectly return" x + y rather than always returning by value (your rewrite is possibly incorrect due to this)
 * It's OK for this apparent function definition to be in a header file despite not including the 'inline' keyword

Does the use of auto as a parameter not also convey that? If it's treated consistently like a template function, I'd think it should.
 
 * It's *not* OK to move this definition out of the header file.

Use of auto as a return type implies that, since the definition must be in the TU.

Nathan Ernst

unread,
Mar 5, 2015, 8:32:38 PM3/5/15
to std-dis...@isocpp.org
* I deliberately want to allow the parameters to have different types
Using auto in this context does not preclude this, if anything it makes indicating you expect the same type harder (impossible?).

 * I deliberately want to allow the return type to differ from those types
Again, I don't see how this is different from the prior argument. Using decltype(a + b) makes it explicit about expectations of the argument types and the return type, but it gives zero guarantees that the return type is same as either 'a' or 'b'.

 * I want a substitution failure if x + y is not valid (your rewrite is possibly incorrect due to this)
This may be a cause for concern, I have no argument/solution to it.

 * I want to "perfectly return" x + y rather than always returning by value (your rewrite is possibly incorrect due to this)
I think this may be a red herring. To perfectly return, wouldn't at least one of the arguments have to be perfectly forwarded? If so, which one? 'x' or 'y' or either? Even then, aren't there facilities to detect such situations already?\

 * It's OK for this apparent function definition to be in a header file despite not including the 'inline' keyword
As it would be a templated function, yes, as every other template function is currently.
 
 * It's *not* OK to move this definition out of the header file.
For the same reason you can't move a templated function definition out of a header currently (or at least out of a scope where all instantiations need to be known).

 * And the big one: it says "this is a template". No need to go scanning the declaration for "auto" (or for concept names, not that you can identify them by sight). It's right there at the start.
I don't really have an argument for this, at all. I can see the value you're asking for. Personally, I would hope to see utilization of this feature more in end-user code, not in libraries. I would hope, and rather, library writers would take the more verbose route utilizing SFINAE & concepts (when available) to give more meaningful errors on incorrect usage.

It's somewhat less clear to me how this loss of readability balances against the possibility of improved readability from a shorter declaration.
 Already, once you've gotten yourself into template metaprogramming land, you already have to run on your 'spidey sense' to determine what's going on. As far as searching code, I've rarely seen 'template' on the same line as the function being defined/declared, and it's even worse if you're looking for a templated member function on a templated class.

All this being said, I don't see anything proposed that prevents you from using the more verbose syntax. And, arguably, I'd like to see the more verbose syntax when I'm utilizing a library, at least in so far as expectations of arguments and returns. I expect this very vague syntax to be at the "end-user" application level or "glue" level.

-Nate

Andrew Sutton

unread,
Mar 5, 2015, 8:50:21 PM3/5/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
>> template<typename ForwardIterator>
>> ForwardIterator next(ForwardIterator);
>>
>> but that's still true if it's rewritten like this:
>>
>> ForwardIterator next(ForwardIterator);
>
>
> That's not what I'm objecting to; I'm objecting to "auto" specifically. But
> since you mention it, this version definitely conveys less information than
> the previous one: it obscures the critical fact that 'next' is a function
> template.

Out of curiosity, why is next's template-ness a critical fact?

I've been writing a fair amount of C lately (and sadly). Many of the
functions I use turn out to be macros. I don't consider that to be a
critical fact. And when I'm writing C++, I generally don't care that
something I call is a template, only that there's an overload that
matches the arguments I call it with.

I've heard this argument before. I've yet to hear a good answer.

Andrew

Nevin Liber

unread,
Mar 5, 2015, 9:10:03 PM3/5/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, Faisal Vali
On 5 March 2015 at 19:50, Andrew Sutton <asutto...@gmail.com> wrote:
Out of curiosity, why is next's template-ness a critical fact?

I've been writing a fair amount of C lately (and sadly). Many of the
functions I use turn out to be macros. I don't consider that to be a
critical fact. And when I'm writing C++, I generally don't care that
something I call is a template, only that there's an overload that
matches the arguments I call it with.

I've heard this argument before. I've yet to hear a good answer.

The two (what I consider to be very minor) concerns I have:

1.  Does the definition belong in a header for correctness?

2.  Unintended code bloat, since every set of types produces a new instantiation.

With the template syntax, you have a very visual way to point that out.  Both auto and concepts are not visually different than a concrete type.  (Well your IDE may be able to address this, but syntactically it isn't visually different).
-- 

Andrew Sutton

unread,
Mar 5, 2015, 9:27:58 PM3/5/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali
> The two (what I consider to be very minor) concerns I have:
>
> 1. Does the definition belong in a header for correctness?

If it declares a function template, then almost certainly.

But as a user who's calling the function, does that matter? The
original comment focused on the information present in the
declaration. From that perspective, I think it matters little how the
function is declared (unless you try to take it's address).

> 2. Unintended code bloat, since every set of types produces a new
> instantiation.
>
> With the template syntax, you have a very visual way to point that out.
> Both auto and concepts are not visually different than a concrete type.
> (Well your IDE may be able to address this, but syntactically it isn't
> visually different).

That's a reasonable concern, but as you say, very minor. I don't think
I've ever chosen to use a different function because it wasn't a
template, but I can envision reasons for doing so :)

Andrew

Andrew Sutton

unread,
Mar 5, 2015, 9:45:41 PM3/5/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
> Right; we need to find a balance where the syntax we have is neither
> unnecessarily terse (to the point of causing readability and maintenance
> problems) nor unnecessarily verbose. It is up to the people proposing the
> change to demonstrate that this requirement is met, and the reactions on
> this thread seem to suggest that we are, so far, lacking a good argument
> that the proposed syntax meets the Goldilocks criterion.

I don't think that there is a single "just right" syntax. Some
declarations simply require heavier syntax (although the template
introduction syntax was added to alleviate some of that). Other
declarations should be able to be expressed simply and directly,
without extra notation.

There is a balance to be reached, but programmers need to find that
for themselves before pre-judging the syntax.

Andrew

Bjarne Stroustrup

unread,
Mar 5, 2015, 10:05:42 PM3/5/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com

(1) people always ask for heavier syntax from new features
(2) people learn
(3) people always complain that the syntax they insisted on is too heavy
handed

I remember serious and well-meaning criticism that allowing "sqrt(2)"
would lead to misuse and bugs and that it was *good* for people and
especially for maintenance if people had to write "sqrt(2.)" or
"sqrt((double)2)" to avoid crashes.

Yes, someone is going to write "void f(auto);" and be surprised. In
particular, someone is going to write "void ff(auto,auto);" and be
surprised that "ff("hello",2)" is allowed, but I think that ship has
sailed. What we really have to get into our/people's heads is that
"auto" is just the weakest constraint. Even a concept that requires
nothing is stronger because "void ff(Unconstrained, Unconstrained);"
will not accept "ff("hello",2)". There are examples that are better
expressed using the less terse notations. We will eventually settle on
conventions for use.

Thiago Macieira

unread,
Mar 5, 2015, 10:09:46 PM3/5/15
to std-pr...@isocpp.org, std-dis...@isocpp.org
On Thursday 05 March 2015 21:27:37 Andrew Sutton wrote:
> > The two (what I consider to be very minor) concerns I have:
> >
> > 1. Does the definition belong in a header for correctness?
>
> If it declares a function template, then almost certainly.
>
> But as a user who's calling the function, does that matter? The
> original comment focused on the information present in the
> declaration. From that perspective, I think it matters little how the
> function is declared (unless you try to take it's address).

That's exactly the point.

When you're just using a token, you may not care too much if it is a macro, a
regular function or a template function. You just want it to do the right job.

But if you look up its definition, it should be clear what it is. The argument
is that with a concept type, the fact that it's a template is hidden unless
you look up every single one of the types in the function's declaration.
Finding out whether it's a template function or a macro may important if you
care for #2 below:

> > 2. Unintended code bloat, since every set of types produces a new
> > instantiation.
> >
> > With the template syntax, you have a very visual way to point that out.
> > Both auto and concepts are not visually different than a concrete type.
> > (Well your IDE may be able to address this, but syntactically it isn't
> > visually different).
>
> That's a reasonable concern, but as you say, very minor. I don't think
> I've ever chosen to use a different function because it wasn't a
> template, but I can envision reasons for doing so :)

I don't think it would be a factor in whether you used it or not. But you may
want to make a note of that for future refactoring of the code, which requires
that you realise that you're doing it.

That said, there are better tools for noticing where the code bloat comes from
than making notes when writing code. We tend to think that the task we're
working on is the single most important thing to have ever happened, when in
the grand scheme of things it might be insignificant.

Herb Sutter

unread,
Mar 5, 2015, 11:20:08 PM3/5/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
Exactly.

Also, the populations of (1) and (3) are different sizes: I can roughly count the number of people (1) I've heard complain that (existing or proposed) C++ syntax is not verbose enough and should be longer, usually in forums like these. I cannot begin to count the number of people (3) I've heard complain that C++ syntax is needlessly verbose, based on their personal experience using the language in their day jobs, usually in comparison with similar features in other languages.


> What we really have
> to get into our/people's heads is that "auto" is just the weakest constraint.
> Even a concept that requires nothing is stronger because "void
> ff(Unconstrained, Unconstrained);" will not accept "ff("hello",2)".

Exactly. Everywhere you see "auto" today, you'll see a concept name tomorrow (if approved). And I think the argument that you wouldn't want to write "auto foo( auto )" definitively evaporates once it's "Concept1 foo( Concept2 x )", and that's the road we're on.

Of all the features proposed for C++17 or 20, I think it's already clear concepts will have the largest effect on the way we write new code. And I think we don't yet quite grok just how broad that effect will be -- I expect most new function templates will routinely use them, but even more than that I suspect that five years from now many (though probably not most) new local variable declarations will likely be typed using concept names, and that right there is a lot of LOC. But the effect could be broader still, so it's good we're going to start getting that experience.

Herb


> -----Original Message-----
> From: Bjarne Stroustrup [mailto:bja...@stroustrup.com]
> Sent: Thursday, March 5, 2015 7:06 PM
> To: c++st...@accu.org
> Cc: std-dis...@isocpp.org; std-pr...@isocpp.org;
> fai...@gmail.com
> Subject: [c++std-core-27217] Re: An implementation of enhanced auto
> deduction and abbreviated template syntax using Clang
>

Tom Honermann

unread,
Mar 5, 2015, 11:45:09 PM3/5/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, fai...@gmail.com
On 03/05/2015 10:05 PM, Bjarne Stroustrup wrote:
> (1) people always ask for heavier syntax from new features
> (2) people learn
> (3) people always complain that the syntax they insisted on is too heavy
> handed

I think there is truth in that. However, I think some other languages
have demonstrated the opposite problem. For example, Perl has been
criticized (fairly or not, I'm not judging) for allowing overly terse
syntax and sometimes termed a "write-only language" due to a common
perception that maintaining Perl code is difficult as a result. I'm not
trying to defend that argument here, just pointing out that the
perception exists.

I think the abbreviated syntax goes too far as currently proposed. It
is hard to imagine a more terse syntax that doesn't require dropping
type placeholders completely. I stated elsewhere in this thread that I
don't mind the current, rather heavy, template syntax, but that doesn't
mean that I wouldn't appreciate a lighter syntax. If there were not
significant semantic differences between template function definitions
and non-template function definitions, then I would love the abbreviated
syntax. The fact is though, that there are significant semantic
differences and some of them are quite subtle.

I don't feel concerned about point of usage of functions declared with
the abbreviated syntax. The behavioral differences aren't that great in
that case. My concern is with maintenance of functions declared with
this syntax and maintainers not realizing that a template is being
modified. Richard supplied an excellent list a few emails back
illustrating some of the problems one can encounter switching a simple
traditionally declared template function to an abbreviated one. I think
his insights should not be overlooked here (or, anywhere else, really).

I would be quite happy with the smallest addition to the proposal that
makes it clear that "this is a template function" and that doesn't rely
on my ability to scan for 'auto' or identify the name of a concept in
the parameter list.

We have this for lambdas:
auto l = [](auto x) { return x; }
If we could do (something like) these for generic functions, I would be
thrilled:
auto <>f(auto x) { return x; }
auto <>f(Iterator i) { return i; }

Tom.

Faisal Vali

unread,
Mar 6, 2015, 12:01:49 AM3/6/15
to Richard Smith, c++std-core, std-dis...@isocpp.org, std-pr...@isocpp.org
On Thu, Mar 5, 2015 at 7:01 PM, Richard Smith <richar...@google.com> wrote:
> On 5 March 2015 at 16:24, Herb Sutter <hsu...@microsoft.com> wrote:
>>
<snip>

* And the big one: it says "this is a template". No need to go scanning the
> declaration for "auto" (or for concept names, not that you can identify them
> by sight). It's right there at the start.
>
> It's somewhat less clear to me how this loss of readability balances against
> the possibility of improved readability from a shorter declaration.
>

+1.

How this fundamental syntactic tension shall resolve itself in time is
a futurity I wish I could claim authority on.

I confess, when *reading* code, I currently prefer to see the template
header to 'warn' me that a template is about to follow (just as i
usually prefer to *read* the type-name when variables are declared) -
but, given this thread, I wonder whether I should require that warning
- and whether it is simply an inertia that serves little useful
purpose. If I am allowed a touch of hyperbole, my worst fear is that
my use of abbreviated syntax shall be inconsistently driven by the
vagaries of an occasionally undisciplineable mood.

John Spicer

unread,
Mar 6, 2015, 9:48:37 AM3/6/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, fai...@gmail.com
I don't think it is very important to the caller, but where next is defined it is important to those maintaining the code.

If ForwardIterator is a constrained-type-specifier, then next is a template, but if ForwardIterator is a type, it is not a template.

At least with "auto" you can figure out from the presence of "auto" that the function is a template.

I agree that the TS is a good chance to get experience and see what people like and don't like, provided that people don't use compatibility with what was specified in the TS for not changing a feature.

One possibility if we wanted some more syntax would be to require a template-introduction (14.2 in the Concepts TS) when a constrained-type-specifier is used, so next would be:

ForwardIterator{T} T next(T);

which, in this case, is shorter than the form without the template introduction.

John.



Nicol Bolas

unread,
Mar 6, 2015, 12:21:16 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
On Thursday, March 5, 2015 at 7:24:32 PM UTC-5, Herb Sutter wrote:

To paraphrase Stroustrup, it’s not about functional programming and object-oriented programming and generic programming… “it’s all just programming.”

 

> Templates are a fundamentally different kind of construct

 

Why? Every full specialization of a function template is just a function.


OK, let's explore this.

Let's say that I'm a novice C++ programmer. I don't really know much about the language. But I have some basic knowledge.

Now, I've been told that when I write functions, I put a prototype in a header file so that other people can use it. But I also put the implementation in a source file, so that it stays hidden. So I write:

//header
RetType func_name(Type1 arg1, ...);

//source
RetType func_name(Type1 arg1, ...)
{
//implementation
}


OK, fine.

I've also been told about a different class of functions: template functions. For reasons I haven't been told and don't much care about (since I'm a novice), I have to put the implementation in the header file. So I know that if I type the word "template", then that function's implementation has to go into a header. So I always do this:

//header
template<typename T>
RetType func_name_template(T arg1, ...)
{
//implementation
}

//source doesn't exist.

 
OK, fine. So... explain to me, the novice C++ programmer, why this doesn't work:

//header
RetType func_name_concept(ConceptName arg1, ...);

//source
RetType func_name_concept(ConceptName arg1, ...)
{
//implementation
}

Explain to me, the novice C++ programmer, why this thing which doesn't look like a template suddenly became a template. Explain to me why I have to implement it in a header, even though it looks exactly like every other non-template function declaration/definition.

To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

Oh, you could say, "well just put everything in a header." That's... insane. Compile times for C++ projects of significant size are already huge even when you try to only put what you need in headers. Adding the burden of shoving everything in a header is crazy.

Now, if you can promise me that the same version of C++ that will include this terse syntax will also include modules, I will immediately stop caring. Once that exists, then most of the differences between template and non-template functions will be erased. And therefore, so too can the syntactic differences.

But so long as there is a difference in how you implement template and non-template functions, I say that there should be an obvious difference in syntax too.

 

> My issue is with, well, any syntax that declares a template without having to type either the word "template" or the use of "<>" brackets.

 

That ship has sailed:

 

                auto plus = [](auto x, auto y) { return x+y; }

 

which even already decays to an ordinary pointer to function, etc.


That doesn't decay into a function pointer. It can't; the operator() is a template.
 

 

Clarifying Q: Are we mainly arguing about whether to require the three characters =, [, and ] ?

Except that there is a difference between creating a lambda (which creates a functor) and creating a function (which can be overloaded).

 

Not only has the ship sailed, but I for one like the direction it’s sailing. I see no reason why functions should be forced to spell “template” and “<>”. What value does it add? It’s “just programming.” In fact, if we didn’t have backward compatibility issues with unnamed parameters and such, I’d personally probably be fine with just “auto plus(x,y){x+y}” as an equivalent function definition. That still doesn’t lose any information.

 

Gratuitous syntax is often unnecessary and usually harmful. Saying

 

                template<class T, class U>

                auto(T x, U y) -> decltype(x+y) { return x+y; }

 

does not appear to me to contain any more information than

 

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

 

does it?

If you take out the late specified return type (I specifically said that static deduction was fine), then I don't see the problem with the first one.

 

Requiring the verbose syntax is gratuitous, if the verbose syntax does not add information, does not serve to disambiguate anything, and does not highlight a dangerous operation or anything else I can see that deserves to have attention called to it.

 

There’s a disturbing (to me and at least some others) trend in C++ these days: People seem to be very prone to wanting “more syntax” lately. It’s rather Vasa-like, if only lexically. Let me channel certain influential committee members and say: ‘People these days are always asking for more syntax! There’s no proposal they’ve seen that they couldn’t make uglier with more syntax!’

 

Important note: The point here is NOT terseness for terseness’ sake. I am not arguing that terser is somehow better, that terseness is virtuous in itself. Too many people glorify languages because they’re terser; fewer characters alone doesn’t make code clearer. Rather, my point is to avoid gratuitous verbosity. At the other end of the pendulum, too many people glorify verbose syntax because they think _that_ is somehow inherently clearer; usually it isn’t. So I am arguing that neither is verbosity virtuous in itself.

 

Herb

The virtue to me of the large syntax of templates is this:

Templates have to be treated differently from non-templates. They have different needs of where their implementations live. And because of those needs, templates make your code compile slower. Even ignoring the compile-time cost of template instantiation, your source has to go in the header. And if that header is included in more than one place, then the source for that template must be recompiled for every place it is included.

Therefore, the bulky template syntax pokes you in the eye every time you write something that's going to compile slower. It immediately lets you know that this function operates under fundamentally different rules than regular functions.

Again, if you could guarantee that we get modules alongside this syntax, I'd be fine, since using templates will not hurt your compile times nearly as much.

Jonathan Wakely

unread,
Mar 6, 2015, 12:38:14 PM3/6/15
to c++std-core, std-dis...@isocpp.org, std-pr...@isocpp.org, Faisal Vali, Herb Sutter
On 6 March 2015 at 17:21, Nicol Bolas wrote:
> Explain to me, the novice C++ programmer, why this thing which doesn't look
> like a template suddenly became a template. Explain to me why I have to
> implement it in a header, even though it looks exactly like every other
> non-template function declaration/definition.
>
> To the novice C++ programmer, it isn't "all just programming." Whether
> something is a template matters.

Ah, the "won't somebody think of the children" argument.

The answer to why it suddenly became a template is that its parameter
is a concept, not a type. A concept is a family of types. I don't see
why that should be much harder to teach than "a function template is a
family of functions" and "a class template is a family of types".

If we're teaching novices how to write C++ templates based on "just
put template<blah> before it and make sure it's in a header" that
doesn't seem like a very sound basis for learning anything more than
arbitrary syntactic rules and cargo cult programming.

(Is it time to trim the CC list so this doesn't continue to be
cross-posted everywhere?)

Tom Honermann

unread,
Mar 6, 2015, 12:46:39 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
On 03/06/2015 12:21 PM, Nicol Bolas wrote:
> Oh, you could say, "well just put /everything/ in a header." That's...
> insane.

and would cause link errors unless also specified as inline. Now the
novice learns to define all their functions as inline functions in a header.

I'm not sure I really buy the novice argument though. I learned this,
others can too.

The real issue to me is that the abbreviated syntax does not permit me
to syntactically determine if a function definition is a template or not
- semantic information is required (unless at least one of the
placeholder types is 'auto').

I don't see modules helping with that.

Tom.

Nicol Bolas

unread,
Mar 6, 2015, 1:01:35 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com

The question there is why you need to "syntactically determine if a function definition is a template or not"? Why do you care? If the compile-time difference is negligible, and you don't need to get a function pointer to it, why would you need to know whether it's a template or not?

Nicol Bolas

unread,
Mar 6, 2015, 1:07:06 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com


On Friday, March 6, 2015 at 12:38:14 PM UTC-5, Jonathan Wakely wrote:
On 6 March 2015 at 17:21, Nicol Bolas wrote:
> Explain to me, the novice C++ programmer, why this thing which doesn't look
> like a template suddenly became a template. Explain to me why I have to
> implement it in a header, even though it looks exactly like every other
> non-template function declaration/definition.
>
> To the novice C++ programmer, it isn't "all just programming." Whether
> something is a template matters.

Ah, the "won't somebody think of the children" argument.

The answer to why it suddenly became a template is that its parameter
is a concept, not a type. A concept is a family of types.  I don't see
why that should be much harder to teach than "a function template is a
family of functions" and "a class template is a family of types".

If a "family of functions" is so fundamentally different from a regular function that it can't be declared/defined in the same way, why does it look exactly like a regular function? If swapping one identifier for another can so radically change how you go about implementing something, shouldn't it be more syntactically obvious that you've made a major change?

Without the template keyword, it doesn't look like a template. And therefore, it is not immediately obvious that it should be treated as such.

Bjarne Stroustrup

unread,
Mar 6, 2015, 1:09:18 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
People will learn. Learning that
    void f(auto);
implies template is kid's play compared to some things we expect people to figure out.

Geoffrey Romer

unread,
Mar 6, 2015, 1:22:36 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, Faisal Vali, Herb Sutter
That's not the case he's talking about. He's talking about this one:

void f(T); 

I don't see how "people will learn" to tell whether that's a template, because there just fundamentally isn't enough information there to answer that question, and in real code the necessary information might be anywhere in the transitive #include graph.

Herb Sutter

unread,
Mar 6, 2015, 1:27:45 PM3/6/15
to Nicol Bolas, std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.

Bjarne Stroustrup

unread,
Mar 6, 2015, 1:32:12 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, Faisal Vali, Herb Sutter
Reminds me of people complaining that they don't know which type Foo is in

    void f(Foo);

and therefore they don't know what arguments it insists.

That can indeed be a real problem, but not one that I loose sleep over.

John Spicer

unread,
Mar 6, 2015, 1:37:35 PM3/6/15
to c++st...@accu.org, Nicol Bolas, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
On Mar 6, 2015, at 1:27 PM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.
 
Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:
 
                auto f() { … };
 
This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

Actually, that is not right -- in fact, it is mostly wrong.

Only if the return type is deduced do you need a definition.

So:

void f(auto,auto);
void g(ForwardIterator);

do not need definitions.

John.

Nevin Liber

unread,
Mar 6, 2015, 1:42:56 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org
On 6 March 2015 at 12:22, 'Geoffrey Romer' via ISO C++ Standard - Discussion <std-dis...@isocpp.org> wrote:

That's not the case he's talking about. He's talking about this one:

void f(T); 

I don't see how "people will learn" to tell whether that's a template, because there just fundamentally isn't enough information there to answer that question, and in real code the necessary information might be anywhere in the transitive #include graph.

There are two audiences (As Andrew pointed out in his reply to my previous message):

1.  The person calling the function.  For the most part, they won't know or care whether or not it is a template function; they just include the correct header and call it.

2.  The person defining the function.  They have to know whether or not it is a template or a specific concrete type, but they had to know that anyway to write the function.

Nevin Liber

unread,
Mar 6, 2015, 1:57:03 PM3/6/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org

On 6 March 2015 at 11:21, Nicol Bolas <jmck...@gmail.com> wrote:

                auto plus = [](auto x, auto y) { return x+y; }

 

which even already decays to an ordinary pointer to function, etc.


That doesn't decay into a function pointer. It can't; the operator() is a template.

This code seems to work:

    using fn = int (*)(int, int);

    fn f = plus;

    std::cout << f(2, 3) << std::endl;

Tony Van Eerd

unread,
Mar 6, 2015, 1:58:23 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
If all we need is auto, then is the next step:

struct X
{
    int x;
    auto y;
};

X is obviously a template?
So is Y:

struct Y
{
    int x;
    ForwardIterator y;
};

‎?

(Again, I'm not actually against 'auto means template function'‎; I just bring up counter arguments to be comfortable that we explored the design space and that we have a path of consistency going forward) 

Tony


Sent from my BlackBerry 10 Turing machine.
From: Bjarne Stroustrup
Sent: Friday, March 6, 2015 1:14 PM
Subject: [c++std-core-27227] Re: An implementation of enhanced auto deduction and abbreviated template syntax using Clang

Tom Honermann

unread,
Mar 6, 2015, 2:04:17 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org
On 03/06/2015 01:42 PM, Nevin Liber wrote:
> There are two audiences (As Andrew pointed out in his reply to my
> previous message):
>
> 1. The person calling the function. For the most part, they won't know
> or care whether or not it is a template function; they just include the
> correct header and call it.
>
> 2. The person defining the function. They have to know whether or not
> it is a template or a specific concrete type, but they had to know that
> anyway to write the function.

I would argue for a third audience (though arguably a subset of the 2nd
case above):

3. The person modifying the function. They have to know whether or not
it is a template or a specific concrete type.

We can say that, if a person changes a function without first
determining that and causes a regression, well shame on them. I think
that is fair. But I think we can do better by offering a little assistance.

Tom.

Andrew Sutton

unread,
Mar 6, 2015, 2:09:28 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
struct X
{
    int x;
    auto y;
};

Ermm... yikes, no. That's like saying that this is a template

void f()
{
  auto x = y;
}

because it has an auto.

I seem to recall some EWG papers or discussion about using auto as the type of a member variable. I don't remember what the outcome was.

(Again, I'm not actually against 'auto means template function'‎; I just bring up counter arguments to be comfortable that we explored the design space and that we have a path of consistency going forward)  

I remember discussing these questions in Bjarne's office years ago... We have explored in this direction, and here be dragons.

Andrew

Andrew Sutton

unread,
Mar 6, 2015, 2:11:50 PM3/6/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org
> I would argue for a third audience (though arguably a subset of the 2nd case
> above):
>
> 3. The person modifying the function. They have to know whether or not it
> is a template or a specific concrete type.
>
> We can say that, if a person changes a function without first determining
> that and causes a regression, well shame on them. I think that is fair.
> But I think we can do better by offering a little assistance.

But do we have to mandate that assistance in every case?

Andrew

Matthew Fioravante

unread,
Mar 6, 2015, 2:14:47 PM3/6/15
to std-pr...@isocpp.org, c++st...@accu.org, std-dis...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com, tvan...@blackberry.com


On Friday, March 6, 2015 at 1:58:23 PM UTC-5, Tony Van Eerd wrote:
If all we need is auto, then is the next step:

struct X
{
    int x;
    auto y;
};

X is obviously a template

Lets have even more fun:

//This is a template
struct A {
 
auto x;
};

//This is not a template
struct B {
 
auto x = 1;
};


(for the record, I'd be happy either way but its good to play devils advocate)

Andrew Sutton

unread,
Mar 6, 2015, 2:24:42 PM3/6/15
to c++st...@accu.org, std-pr...@isocpp.org, std-dis...@isocpp.org, Faisal Vali, Herb Sutter, tvan...@blackberry.com
> //This is a template
> struct A {
> auto x;
> };

No, it's not. Something in the declaration shouldn't change the nature
of its declaration (apparently except deduced return types). And here's why:

struct A; // Is this a template? Clearly not

struct A {
auto x; // Makes A a template?
};

That's just insane.

Andrew

Tom Honermann

unread,
Mar 6, 2015, 2:26:30 PM3/6/15
to std-pr...@isocpp.org, std-dis...@isocpp.org, c++st...@accu.org, fai...@gmail.com, hsu...@microsoft.com
On 03/06/2015 01:01 PM, Nicol Bolas wrote:
> The question there is why you need to "syntactically determine if a
> function definition is a template or not"? Why do you care? If the
> compile-time difference is negligible, and you don't need to get a
> function pointer to it, why would you need to know whether it's a
> template or not?

Because this:

void f(X&& x) {}

may be called with an rvalue or lvalue argument if X is a concept, but
may only be called with an rvalue if X is a type. That may be important
to a library interface.

And because this:

void f(X x) {
static int invoke_count;
++invoke_count;
}

will maintain a count of either every invocation of f() or every
invocation of an instantiation of f() depending on whether X is a
concept or not.

And because this:

void f(X x) {}

may be moved from a primary source file to a header if X is a concept,
but not if X is a type.

And because this:

void f(X x) {
X::type t;
}

will require 'typename' if X is a concept, but will not allow it if X is
not (of course, the compiler will be happy to tell me about this one).

Why do I care about the above? Because, in a large code base that I'm
not familiar with, having to go find out what X is detracts from getting
the work done.

Tom.

Geoffrey Romer

unread,
Mar 6, 2015, 2:27:23 PM3/6/15
to c++st...@accu.org, Nicol Bolas, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
On Fri, Mar 6, 2015 at 10:27 AM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.


This very much matches my experience- as far as I can tell, the vast majority of C++ code is non-template code. But why is that surprising, and why do you expect concepts to change it?

Scott Prager

unread,
Mar 6, 2015, 2:28:44 PM3/6/15
to std-dis...@isocpp.org, std-pr...@isocpp.org, c++st...@accu.org, fai...@gmail.com, hsu...@microsoft.com, tvan...@blackberry.com, fmatth...@gmail.com
These examples seem rather farcical to me. How would we instantiate such a
type? At least with functions, we get implicit specialization based on the
arguments supplied, but with types... to make it feasible, we'd have to enable
this syntax:

std::pair p{x, std::ref(y)};  // std::pair<X, Y&>

...and I don't see that happening. I think the analogy of template classes to
template functions is apples to oranges since they operate by very different
rules.

(Not that I don't think the above syntax would be great, just not as feasible.)

Faisal Vali

unread,
Mar 6, 2015, 2:29:54 PM3/6/15
to Andrew Sutton, std-dis...@isocpp.org, std-pr...@isocpp.org, hsu...@microsoft.com
[dropping core]


On Fri, Mar 6, 2015 at 1:09 PM, Andrew Sutton <asutto...@gmail.com> wrote:
>> struct X
>> {
>> int x;
>> auto y;
>> };
>
>
> Ermm... yikes, no. That's like saying that this is a template
>
> void f()
> {
> auto x = y;
> }
>
> because it has an auto.
>
> I seem to recall some EWG papers or discussion about using auto as the type
> of a member variable. I don't remember what the outcome was.
>

http://www2.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3897.html

Scott Prager

unread,
Mar 6, 2015, 2:36:56 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com, bja...@stroustrup.com


On Friday, March 6, 2015 at 1:32:12 PM UTC-5, Bjarne Stroustrup wrote:
 
Reminds me of people complaining that they don't know which type Foo is in

    void f(Foo);

and therefore they don't know what arguments it insists.

That can indeed be a real problem, but not one that I loose sleep over.

Examples like this, whether Foo  is a concept or concrete type, made me
consider that functions with concept arguments should be labeled as
templates... but then I realized the contradiction: If Foo is a type and one
wants to call it, one must look up Foo's declaration. Therefor, Foo being a
concept doesn't actually require any more or less knowledge of the code base
than it being a type. In either case, the declaration must be looked up.

Tom Honermann

unread,
Mar 6, 2015, 2:49:04 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org
But do we have to obscure the nature of the function in any cases?

What advantage is gained by eliminating the need for a single 'template'
or other "this-is-a-template" identifier on the function declaration.
Saving keystrokes on a single token doesn't strike me as a big win.

Is your view that allowing template and non-template functions to share
a common declaration syntax makes C++ simpler? From my perspective, it
actually makes the language more difficult because it obscures
semantically relevant details.

Tom.

Nicol Bolas

unread,
Mar 6, 2015, 3:11:39 PM3/6/15
to std-dis...@isocpp.org, c++st...@accu.org, jmck...@gmail.com, std-pr...@isocpp.org, fai...@gmail.com, gro...@google.com


On Friday, March 6, 2015 at 2:27:23 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 10:27 AM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.


This very much matches my experience- as far as I can tell, the vast majority of C++ code is non-template code. But why is that surprising, and why do you expect concepts to change it?


That's my experience as well. However, I can also say that concepts is not what would get me to write more templates, as concepts (as it is currently proposed) only makes using templates easier (by declaring up-front what the requirements are). It doesn't make implementing a function easier (by checking each point of use to see if it is a required behavior).

Even with that, it wouldn't make me write more templates. I'd still need modules for that; compile times are just too long for heavily templated code. Debugging and testing requires lots of compilation, so things that make compilation slower will (continue to) be avoided.

I just wish I didn't have to avoid useful language features because of the compilation mechanism.

Herb Sutter

unread,
Mar 6, 2015, 3:54:16 PM3/6/15
to c++st...@accu.org, Nicol Bolas, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com

This surprised me so I asked John offline what he meant, and I think we’re not in disagreement. You can’t call those unless there are (also) definitions.

 

What I said is correct: If auto (or a concept name) is used in the return type or parameter type, the definition must be available “in a header.” And this is already true for auto return types.

 

I did not mean to imply that you couldn’t also have a forward declaration too (which you can have for function templates but not for auto returns), but it still must be accompanied by a definition which was the point under discussion, namely that the definition still has to be available in the header.

 

Note that I’m excluding the “extern template” case, which is a special case and about controlling where instantiations occur (or limiting them) rather than about writing the generally usable function template itself… so IMO extern templates aren’t applicable to this question.

 

Herb

John Spicer

unread,
Mar 6, 2015, 3:58:03 PM3/6/15
to c++st...@accu.org, Nicol Bolas, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com
I think the confusion is that Herb wrote:

“if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

If you say "auto" or a concept name, it is a template.   My interpretation of what Herb wrote, is that it was implying more than that.

john.

Geoffrey Romer

unread,
Mar 6, 2015, 4:25:51 PM3/6/15
to Nicol Bolas, std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, Faisal Vali
On Fri, Mar 6, 2015 at 12:11 PM, Nicol Bolas <jmck...@gmail.com> wrote:


On Friday, March 6, 2015 at 2:27:23 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 10:27 AM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.


This very much matches my experience- as far as I can tell, the vast majority of C++ code is non-template code. But why is that surprising, and why do you expect concepts to change it?


That's my experience as well. However, I can also say that concepts is not what would get me to write more templates, as concepts (as it is currently proposed) only makes using templates easier (by declaring up-front what the requirements are). It doesn't make implementing a function easier (by checking each point of use to see if it is a required behavior).

Interesting; my impression was the other way around, that concepts make it easier to write templates, but not really easier to use them. The main functional advantage that I see with concepts is that they let you control the overload set much more easily (and much more readably), and that helps template authors, not template users. I see your point about declaring the requirements up-front, but decent template libraries already do that in the documentation; I'm not sure that formalizing those requirements in code will really help users much.

Herb Sutter

unread,
Mar 6, 2015, 4:31:16 PM3/6/15
to c++st...@accu.org, Nicol Bolas, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com

Sorry for confusion, I was trying to word it generally to cover both auto returns (which we have already, so we already have a case where we require a definition without a keyword like “template” or “inline”) and the proposed auto parameter (only the latter makes a template).

 

The observation was that both the current and proposes uses of “auto” in the declaration would equally require a definition to be available in the header, and that simply saying that is a teachable rule.

 

Thanks,

Nicol Bolas

unread,
Mar 6, 2015, 5:23:17 PM3/6/15
to std-dis...@isocpp.org, jmck...@gmail.com, c++st...@accu.org, std-pr...@isocpp.org, fai...@gmail.com, gro...@google.com


On Friday, March 6, 2015 at 4:25:51 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 12:11 PM, Nicol Bolas <jmck...@gmail.com> wrote:


On Friday, March 6, 2015 at 2:27:23 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 10:27 AM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.


This very much matches my experience- as far as I can tell, the vast majority of C++ code is non-template code. But why is that surprising, and why do you expect concepts to change it?


That's my experience as well. However, I can also say that concepts is not what would get me to write more templates, as concepts (as it is currently proposed) only makes using templates easier (by declaring up-front what the requirements are). It doesn't make implementing a function easier (by checking each point of use to see if it is a required behavior).

Interesting; my impression was the other way around, that concepts make it easier to write templates, but not really easier to use them. The main functional advantage that I see with concepts is that they let you control the overload set much more easily (and much more readably), and that helps template authors, not template users. I see your point about declaring the requirements up-front, but decent template libraries already do that in the documentation; I'm not sure that formalizing those requirements in code will really help users much.

You assume that users actually read that documentation. Or remember it when they read it.

If someone gives you an abstract base class to implement, the requirements are listed right there, in the language. You have to derive from that class; derive from the wrong one, and you'll get a compiler error somewhere. You have to override all pure-virtual methods; type the method name wrong, and you get a compiler error somewhere (either due to the class still being abstract or because you used "override" and there was no base class function). And so forth.

If I give a non-moveable type to std::vector<T>, it will give me some kind of compiler error. What kind? God only knows, but more likely than not, it will be long, obtuse, and generally indecipherable if you've never seen it before. This is because the compilation failure happens somewhere in the instantiation of std::vector<T> when it tries to actually use your type in a way that it can't be used. So the compiler will point to the guts of std::vector<T>'s implementation, rather than at your code where the actual mistake was made.

If I give a non-moveable type to std::vector<MoveConstructable>, it will give me a much cleaner error message. With a semi-decent compiler, it'll point you right to the line where you instantiated your std::vector and say "Hey, your type T isn't MoveConstructable, because it doesn't have a move constructor." At the very least, I won't get a giant spew of template stuff.

Concepts are great at telling me what I did wrong when I misuse a template. Which means I will feel much more confident that, if it compiled, I'm using the template correctly.

Geoffrey Romer

unread,
Mar 6, 2015, 7:33:34 PM3/6/15
to Nicol Bolas, std-dis...@isocpp.org, c++st...@accu.org, std-pr...@isocpp.org, Faisal Vali
On Fri, Mar 6, 2015 at 2:23 PM, Nicol Bolas <jmck...@gmail.com> wrote:


On Friday, March 6, 2015 at 4:25:51 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 12:11 PM, Nicol Bolas <jmck...@gmail.com> wrote:


On Friday, March 6, 2015 at 2:27:23 PM UTC-5, Geoffrey Romer wrote:

On Fri, Mar 6, 2015 at 10:27 AM, Herb Sutter <hsu...@microsoft.com> wrote:

> To the novice C++ programmer, it isn't "all just programming." Whether something is a template matters.

 

Why? Only because of where you put the definition, and that’s (a) teachable and (b) not new because the same issue exists already with:

 

                auto f() { … };

 

This is not a template, but must appear in a header. This is amazingly similar – and easy to teach as “if the declaration mentions ‘auto’ or a concept name, the compiler needs the definition, either to deduce something or to inline the body into the caller.” Right?

 

Herb

 

PS – Since you mention “novices” writing templates, in my experience (and to my surprise) I’ve found that not only novices but also intermediate developers (like 5-7 year veterans) don’t write templates very much. [I expect this to change with concepts, for the good.] I discovered this by chance when I had a class exercise that included writing a very simple template, and as I walked through the class during the exercise I was surprised that most of the groups asked about the syntax for writing a template – a dead giveaway that they didn’t write templates very often, yet these were pretty experienced developers who used C++ every day, but just never needed to write templates much in their normal code. To validate that this wasn’t just an outlier group, I’ve watched that exercise in a number of classes over several years and found a similar result – the majority of even reasonably experienced C++ programmers asked about the syntax for how to write a template.


This very much matches my experience- as far as I can tell, the vast majority of C++ code is non-template code. But why is that surprising, and why do you expect concepts to change it?


That's my experience as well. However, I can also say that concepts is not what would get me to write more templates, as concepts (as it is currently proposed) only makes using templates easier (by declaring up-front what the requirements are). It doesn't make implementing a function easier (by checking each point of use to see if it is a required behavior).

Interesting; my impression was the other way around, that concepts make it easier to write templates, but not really easier to use them. The main functional advantage that I see with concepts is that they let you control the overload set much more easily (and much more readably), and that helps template authors, not template users. I see your point about declaring the requirements up-front, but decent template libraries already do that in the documentation; I'm not sure that formalizing those requirements in code will really help users much.

You assume that users actually read that documentation. Or remember it when they read it.

If someone gives you an abstract base class to implement, the requirements are listed right there, in the language. You have to derive from that class; derive from the wrong one, and you'll get a compiler error somewhere. You have to override all pure-virtual methods; type the method name wrong, and you get a compiler error somewhere (either due to the class still being abstract or because you used "override" and there was no base class function). And so forth.

_Some_ of the requirements are embedded in the code, but not all. Those methods I'm overriding probably have contracts, and the compiler will not be able to tell me when I violate them. There's just no helping the programmers who don't read the documentation, but I think they're a minority.
 

If I give a non-moveable type to std::vector<T>, it will give me some kind of compiler error. What kind? God only knows, but more likely than not, it will be long, obtuse, and generally indecipherable if you've never seen it before. This is because the compilation failure happens somewhere in the instantiation of std::vector<T> when it tries to actually use your type in a way that it can't be used. So the compiler will point to the guts of std::vector<T>'s implementation, rather than at your code where the actual mistake was made.

If I give a non-moveable type to std::vector<MoveConstructable>, it will give me a much cleaner error message. With a semi-decent compiler, it'll point you right to the line where you instantiated your std::vector and say "Hey, your type T isn't MoveConstructable, because it doesn't have a move constructor." At the very least, I won't get a giant spew of template stuff.

Concepts are great at telling me what I did wrong when I misuse a template. Which means I will feel much more confident that, if it compiled, I'm using the template correctly.

I grant you that concepts have the potential to improve template error messages, but as your example showed, the errors that they catch tend to be errors that would have been caught anyway by ordinary type checking, so I don't see how your increased confidence can be justified.

Vicente J. Botet Escriba

unread,
Mar 7, 2015, 11:51:11 AM3/7/15
to std-dis...@isocpp.org, Bjarne Stroustrup, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
Le 06/03/15 19:58, Tony Van Eerd a écrit :
If all we need is auto, then is the next step:

struct X
{
    int x;
    auto y;
};

X is obviously a template?
So is Y:

struct Y
{
    int x;
    ForwardIterator y;
};

‎?

(Again, I'm not actually against 'auto means template function'‎; I just bring up counter arguments to be comfortable that we explored the design space and that we have a path of consistency going forward) 


While for template functions the type is deduced, how could you deduce the type for auto or ForwardIterator. How would you declare an instance of X, or a parameter of type X.

X<???> v;

what if we had

struct X
{
    auto x;
    auto y;
};

X<???, ???> v;

Should the parameters need to be given in the order of declaration of the auto/Concept data members?

I find this confusing.

Vicente

Jonathan Wakely

unread,
Mar 7, 2015, 12:20:44 PM3/7/15
to c++std-core, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
This wild speculation seems off-topic on c++std-core, can it be
continued just at std-discussion and/or std-proposals?

David Rodríguez Ibeas

unread,
Mar 7, 2015, 4:17:56 PM3/7/15
to std-dis...@isocpp.org, c++std-core, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
When I went over the concepts paper there were a couple of things that troubled me a bit (not a lot) and that are relevant to this discussion.  The first one is that the syntax does not call out that the identifier names a concept.  This is also the case in C++14, C++11 and C++03, so nothing new, just adding one more dimension (before, a new type could be added that changed the meaning of an identifier), but with concepts and a non-distinguishible syntax now we have more interactions.

The second thing that concerned me is the variety of syntaxes to represent constrained templates.  This is driven by two conflicting goals: terseness and expressive power.  In addition to that, I disliked the fact that the use of a place-holder type has different semantics: 'void f(auto x, auto y)' introduces two unrelated types for a and b, while 'void f(concept a, concept b)' introduces a single type for both a and b.

An alternative syntax that came to mind, was to use the syntax for the template introduction as a placeholder: 'void f(concept{T} x, concept{U} y)' would introduce two types T and U, both satisfying the 'concept' after the introduction of the type with 'concept{T}', the identifier T could be reused to represent the same type for different parameters: 'void f(concept{T} x, T y)' [equivalent to the Concepts TS: 'void f(concept x, concept y)'.  Compared with the previous syntax, there is a bit of overhead, but I don't consider that to be a *lot* of overhead.  Another advantage of this syntax is that in a concise form you can allow for multiple arguments to have different types satisfying the same concept: 'bool equal(FwdIter{It1} first, It1 last, FwdIter{It2} first2, It2 last2)'.  This is currently not allowed in the concepts TS with the more concise syntax.

As far as I know, this syntax is illegal in the language at this point, so it is clearly identifiable as relating to a concept, and could even be used to drive lookup to ignore types when searching for the identifier 'concept'.  The same syntax could be allowed (not required) for the auto placeholder to enable an unconstrained template in which two arguments are of the same type: void f(auto{T} x, T y).

Similar to the template introduction case, it would be possible to use the syntax to introduce multiple types at once: 'bool equal(Comparable{T,U} const & x, U const & y) { return x == y; }' If this is allowed, there would not be a need to have the template introduction syntax. This is really the same thing, except that it would not appear outside of the argument list, but inlined with the parameters, which makes it a valid alternative for lambas [](Comparable{T,U} const & x, U const & y) { return x == y; }.

Whether this is the good solution or something else is, I'd like to have less alternative syntaxes, and I am willing to pay a bit on terseness (this is not a huge difference) for clarity, reducing the alternatives and flexibility.

    David

* An open question, for which I don't have a good answer is whether the syntax should be composable: bool f(concept1{concept2{T}, concept3{U}} t, U u) meaning:

template <typename T, typename U> 
requires concept2<T> and concept3<U> and concept1<T,U> // pseudo code, not sure if this is valid syntax
bool f(T t, U u);

* One thing that bothers me of this syntax (but that is also a problem in the template introduction one) is whether all identifiers inside the {} create new template parameters or if we can find a way of referring to identifiers in the scope of the declaration:

void f(auto{T} t) {
   [=t](Comparable{U,T} x) { return u == t; } // 1
}

Is there a possible concise syntax that unambiguously allows us to state that 'T' is not a type introduced by 'Comparable{U,T}'? I have considered some alternatives but I am not too fond of any of them, the one that seems lighter would be abusing additional curlies:

Comparable{T, {U}} t // This introduces a new type T, but looks up U in the current scope, requires Comparable<T,U>, decltype(t) == T
Comparable{{T}, U} u // This introduces a new type U, but looks up T in the current scope, requires Comparable<T,U>, decltype(u) == U (i.e. the syntax 'concept{x,y,z}' is equivalent to introducing the unescaped (by lack of a better name) types as template arguments and the subsitution of the placeholder for the first such introduced type.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-discussion/.

Bjarne Stroustrup

unread,
Mar 7, 2015, 4:55:49 PM3/7/15
to c++st...@accu.org, std-dis...@isocpp.org, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
If someone has a proposal for changes to the concepts TS, I suggest they write a paper for the evolution group to consider.

We have discussed "auto" and concepts for years (I first described "void f(auto);" to the EWG in 2004 or so) and I have seen little new or in terms of facilities or technical arguments in this long thread.

Tony Van Eerd

unread,
Mar 7, 2015, 5:18:24 PM3/7/15
to David Rodríguez Ibeas, std-dis...@isocpp.org, c++std-core, std-pr...@isocpp.org, fai...@gmail.com, hsu...@microsoft.com
For the in-scope case, did you consider :U which is similar to ::U (which would be U in the global scope)?


Sent from my BlackBerry 10 Turing machine.
From: David Rodríguez Ibeas
Sent: Saturday, March 7, 2015 4:21 PM
Subject: [c++std-core-27261] Re: [std-discussion] Re: Re: An implementation of enhanced auto deduction and abbreviated template syntax using Clang
Reply all
Reply to author
Forward
0 new messages