Has it been proposed to allow "template <...>" to apply to multiple declarations/definitions?

211 views
Skip to first unread message

eya...@technion.ac.il

unread,
Apr 23, 2017, 3:54:48 PM4/23/17
to ISO C++ Standard - Future Proposals
Hello,

This is my first post to this, um, list/group, so please indulge any flagrant ignorance.

When writing templated code, we often find ourselves writing multiple consecutive functions with identical template parameters. (As an example, we can have a look at, say, libstdc++'s bits/stl_algo.h ;  or just any templated class with multiple methods implemented outside of the class definition).

For a long while now I've been wondering why it is that we have to do so, i.e. write code such as

template <typename T> void foo();
template <typename T> void bar();

rather than

template <typename T> {
    void foo();
    void bar();
}

?

To clarify, I mean having the latter as merely a syntactic-sugar-equivalent to the former, without intricating the two definitions/declarations in any way. Now, of course when you put things together visually you're implying they're somehow related, but that would only be a stylistic nuance, and - as far as I can tell - should not influence anything beyond parsing.

The thing is, that seems a relatively obvious and intuitive idea - so somebody must have proposed  it, or something similar, already. Searching this group's archives I found this post:
https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/template$20scope/std-proposals/ficfBQIgR4c/FRPjJ1QFcjoJ
part of which is very similar to what I suggest, except for involving namespaces and/or class method implementations specifically - which might be interesting but also problematic (increasing the cost side of a cost/benefit view). My thought was about the absolute-minimum-cost suggestion. That thread did not end in any conclusive way, nor in references to past discussions.

So, my questions to the group:
  • Has this been more extensively/seriously proposed and discussed before?
  • If so, can you refer me to the text of such discussions or decisions?
  • If not, would this have some obvious downside/cost which I'm missing?
  • Ville Voutilainen mentioned, on that thread, a much more far-reaching idea, of having a "with foo bar" construct in C++; I would also be interested in the history of that (perhaps for inspiration regarding my simpler idea)

Respectfully,

Eyal Rozenberg

Jens Maurer

unread,
Apr 23, 2017, 4:38:57 PM4/23/17
to std-pr...@isocpp.org
On 04/23/2017 09:54 PM, eya...@technion.ac.il wrote:
> template<typenameT> {
> void foo();
> void bar();
> }

Looks like a reasonable proposal to me. I'm not aware of recent
discussions on a proposal similar to this, but Ville knows a lot
more about that.

The proposal needs to be clarified regarding nesting:

template<class T>
template<class U> {
void f();
}

and

template<class T> {
template<class U> {
void f();
}
void g();
}


(Two levels of template headers; are both options allowed?)

Jens

d25f...@outlook.com

unread,
Apr 23, 2017, 4:46:44 PM4/23/17
to std-pr...@isocpp.org
>
> On 24 Apr 2017, at 03:54, eya...@technion.ac.il wrote:
>
> Hello,
>
> This is my first post to this, um, list/group, so please indulge any flagrant ignorance.
>
> When writing templated code, we often find ourselves writing multiple consecutive functions with identical template parameters. (As an example, we can have a look at, say, libstdc++'s bits/stl_algo.h ; or just any templated class with multiple methods implemented outside of the class definition).

Defining members of a template class outside the class is a pain..

>
> For a long while now I've been wondering why it is that we have to do so, i.e. write code such as
>
> template <typename T> void foo();
> template <typename T> void bar();

Since for the above declarations, 'T' for 'foo' and 'bar' are not required to be the same (since they can't be related anyway),

> rather than
>
> template <typename T> {
> void foo();
> void bar();
> }
>
> ?

neither should the 'T' here be..

And that makes confusion. At the first sight, 'foo' and 'bar' seems to share a same 'T' somehow, just as what we have 'T' for (member functions of) class templates today.

> To clarify, I mean having the latter as merely a syntactic-sugar-equivalent to the former, without intricating the two definitions/declarations in any way. Now, of course when you put things together visually you're implying they're somehow related, but that would only be a stylistic nuance, and - as far as I can tell - should not influence anything beyond parsing.

And that's not what we should do from the design perspective IMHO.
Grouping things that are not logically related together makes the code hard to maintain. Think about the efforts needed to add another template argument for one of the functions in the 'template <typename T> {...}' scope.

> The thing is, that seems a relatively obvious and intuitive idea - so somebody must have proposed it, or something similar, already. Searching this group's archives I found this post:
> https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/template$20scope/std-proposals/ficfBQIgR4c/FRPjJ1QFcjoJ
> part of which is very similar to what I suggest, except for involving namespaces and/or class method implementations specifically - which might be interesting but also problematic (increasing the cost side of a cost/benefit view). My thought was about the absolute-minimum-cost suggestion. That thread did not end in any conclusive way, nor in references to past discussions.
>
> So, my questions to the group:
> • Has this been more extensively/seriously proposed and discussed before?
> • If so, can you refer me to the text of such discussions or decisions?
> • If not, would this have some obvious downside/cost which I'm missing?
> • Ville Voutilainen mentioned, on that thread, a much more far-reaching idea, of having a "with foo bar" construct in C++; I would also be interested in the history of that (perhaps for inspiration regarding my simpler idea)
> Respectfully,
>
> Eyal Rozenberg

As a side note, also check to see Concepts TS (n4377). Although it seems not to (completely) address your issue, when the template arguments are used to declare function parameters, it does simplify:

template <typename T> void foo(T arg);

into:

void foo(auto arg);

given that T is not (heavily) used.

>
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0f4715ef-223b-4d28-8381-d7a43b93d792%40isocpp.org.

Jens Maurer

unread,
Apr 23, 2017, 5:07:08 PM4/23/17
to std-pr...@isocpp.org
On 04/23/2017 10:46 PM, d25f...@outlook.com wrote:
>> For a long while now I've been wondering why it is that we have to do so, i.e. write code such as
>>
>> template <typename T> void foo();
>> template <typename T> void bar();
>
> Since for the above declarations, 'T' for 'foo' and 'bar' are not required to be the same (since they can't be related anyway),

Sure, but the main use case for this feature is probably

template<class T>
void C<T>::foo()
{ ... }

template<class T>
void C<T>::bar()
{ ... }

where the "T"s are, in fact, related.

> And that's not what we should do from the design perspective IMHO.
> Grouping things that are not logically related together makes the code hard to maintain. Think about the efforts needed to add another template argument for one of the functions in the 'template <typename T> {...}' scope.

Just move that particular function declaration / definition out of the template<...> { ... } scope?
Seems not exceedingly difficult.

> As a side note, also check to see Concepts TS (n4377). Although it seems not to (completely) address your issue, when the template arguments are used to declare function parameters, it does simplify:
>
> template <typename T> void foo(T arg);
>
> into:
>
> void foo(auto arg);
>
> given that T is not (heavily) used.

In a conceptified landscape, I expect plain (unconstrained) "T"
not to be used frequently, so the "auto" rewrite isn't important
to me. (Personally, I feel we should have a template header for
a template, but I understand there are other opinions that want
to make templates look like regular functions as much as possible.)

Jens

eya...@technion.ac.il

unread,
Apr 23, 2017, 5:14:02 PM4/23/17
to ISO C++ Standard - Future Proposals
About nesting:
Frankly, I had not given that thought, since I essentially never write nested templates at file scope (as opposed to templated methods of a templated class). However, I think it would be consistent if any declaration/definition would "traverse upwards" the chain of `template <...> indicators surrounding it --- just like it does now, IIANM, except that it would respect curly braces rather than just directly-preceding templating indicators --- and be translated/transcribed to a non-block-scoped nested-template declaration/definition, so that this:


template<class T>
template<class U> {
 
void f();
}
becomes this:

template<class T> template<class U> void f();

and this:

template<class T> {
 
template<class U> {
   
void f();
 
}
 
void g();
}
becomes this:
template<class T> template<class U> void f();
template<class T> void g();

I hope you're not trying to lay an inconsistency trap for me though :-)

Eyal Rozenberg

unread,
Apr 23, 2017, 5:24:16 PM4/23/17
to std-pr...@isocpp.org


On 04/23/2017 10:46 PM, d25f...@outlook.com wrote:
> And that makes confusion. At the first sight, 'foo' and 'bar' seems to share a same 'T' somehow, just as what we have 'T' for (member functions of) class templates today.

I see where you're coming from. However, if you spend a second to think
about it, you remember than T is just a parameter. You're not setting T,
you're just using it as a formal parameter. You can instantiate foo()
with different T's and it is meaningless to say "instantiate bar with
the same T"s - it's any T.

Also, it's not very dissimilar from having

void foo(int conspicuous_name);
void bar(int conspicuous_name);

which makes you suspect that the arguments to foo() and to bar() are
related somehow.


> And that's not what we should do from the design perspective IMHO.
> Grouping things that are not logically related together makes the code
hard to maintain. Think about the efforts needed to add another template
argument for one of the functions in the 'template <typename T> {...}'
scope.

Well...

1. it's the programmer who has the choice of whether or not to perform
that grouping. For entirely unrelated declarations/definitions, it would
make better sense to break up the grouping.
2. When two functions are declared or defined consecutively, they're
usually are related.

> As a side note, also check to see Concepts TS (n4377).

I'll have a look, thank you.

Eyal

Péter Radics

unread,
Apr 24, 2017, 4:14:12 AM4/24/17
to ISO C++ Standard - Future Proposals, d25f...@outlook.com


On Sunday, April 23, 2017 at 10:46:44 PM UTC+2, d25f...@outlook.com wrote:
>
> On 24 Apr 2017, at 03:54, eya...@technion.ac.il wrote:
>
> Hello,
>
> This is my first post to this, um, list/group, so please indulge any flagrant ignorance.
>
> When writing templated code, we often find ourselves writing multiple consecutive functions with identical template parameters. (As an example, we can have a look at, say, libstdc++'s bits/stl_algo.h ;  or just any templated class with multiple methods implemented outside of the class definition).

Defining members of a template class outside the class is a pain..


There was a proposal a while back about "Class Namespace" (a quick search brings up this link, but I'm not sure this is the latest draft: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html).  This proposal is smaller in scope then the OPs idea, but would solve the issue for class templates.

I started working on the implementation in clang, but unfortunately I got distracted... (I have the syntax handled but no semantic actions).

regards,
mitch

eya...@technion.ac.il

unread,
Apr 24, 2017, 11:18:06 AM4/24/17
to ISO C++ Standard - Future Proposals, d25f...@outlook.com
I actually think that's a more complicated suggestion, since it requires some resolution work to find the right class. On the other hand, it better addresses the annoyance of having to repeat lots of text when implementing class methods.

But be that as it may - what's the status of that proposal? I see that it's been 'assigned' to the Evolution subgroup; should I post to that mailing lists about this whole business?

Also, do you think it's reasonable/advisable to draft a proposal in a similar format and submit it more officially?

Matthew Woehlke

unread,
Apr 25, 2017, 10:57:16 AM4/25/17
to std-pr...@isocpp.org, d25f...@outlook.com
On 2017-04-24 11:18, eya...@technion.ac.il wrote:
> On Monday, April 24, 2017 at 10:14:12 AM UTC+2, Péter Radics wrote:
>> There was a proposal a while back about "Class Namespace" (a quick search
>> brings up this link, but I'm not sure this is the latest draft:
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html).

It is. I didn't get a chance to present it at Jacksonville, but the
informal feedback I received was that it needed more work. (Alas, now I
can't recall what folks were wanting...)

>> This proposal is smaller in scope then the OPs idea, but would solve the
>> issue for class templates.
>
> I actually think that's a more complicated suggestion, since it requires
> some resolution work to find the right class.

How so? It's a fairly straight-forward transformation. This:

[TEMPLATE] // template <...>
namespace CLASS_SPEC {
TYPE DECL // e.g. int foo(...)
}

...is equivalent to:

[TEMPLATE] TYPE CLASS_SPEC::DECL

...and very nearly equivalent to:

[TEMPLATE] CLASS_SPEC {
TYPE DECL
};

I don't see why the compiler would have to work any harder under the
proposal than it already needs to today. A simple implementation can
just memoize the namespace tokens and then transform every declaration
within the scope using said tokens to match its C++current equivalent.

> But be that as it may - what's the status of that proposal? I see that it's
> been 'assigned' to the Evolution subgroup; should I post to that mailing
> lists about this whole business?

See above. Needs to be presented. Feedback is always appreciated!

> Also, do you think it's reasonable/advisable to draft a proposal in a
> similar format and submit it more officially?

Please talk to me before submitting a similar proposal; it is probably
better to update the existing proposal instead, unless you are proposing
something significantly different. (Even if you want to propose an
alternative, maybe I would like to help :-).)

--
Matthew

Avi Kivity

unread,
Apr 25, 2017, 11:28:39 AM4/25/17
to std-pr...@isocpp.org, Jens Maurer


On 04/24/2017 12:07 AM, Jens Maurer wrote:
> On 04/23/2017 10:46 PM, d25f...@outlook.com wrote:
>>> For a long while now I've been wondering why it is that we have to do so, i.e. write code such as
>>>
>>> template <typename T> void foo();
>>> template <typename T> void bar();
>> Since for the above declarations, 'T' for 'foo' and 'bar' are not required to be the same (since they can't be related anyway),
> Sure, but the main use case for this feature is probably
>
> template<class T>
> void C<T>::foo()
> { ... }
>
> template<class T>
> void C<T>::bar()
> { ... }
>
> where the "T"s are, in fact, related.

Perhaps we should address this directly:

template <class T>
namespace class C<T> {
void foo() { ... }
void bar() { ... }
};


"namespace class" means that any top-level identifiers are now in the
named class. It does not allow declaring new names, and definitions are
not implied inline. It just changes the meaning of "foo" to template
<class T> class C<T>::foo.

Avi Kivity

unread,
Apr 25, 2017, 11:31:37 AM4/25/17
to std-pr...@isocpp.org, Jens Maurer
A few responses below, I see it's already a proposal:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html)

Eyal Rozenberg

unread,
Apr 29, 2017, 12:49:43 PM4/29/17
to std-pr...@isocpp.org, d25f...@outlook.com
I've had another look at your suggestion, Matthew. I've now bought into
your explanation of why it's not really more complicated than what I
suggested. So - I like it.

But there's a bit of a conundrum here. Your proposal makes sense. I also
think my proposal makes sense, and the justification is at least
partially similar, i.e. "Why should a template specification apply to
just a single definition/declaration?" as an example of DRY. Both
proposals are not complicated to implement, it seems.

Now, your suggestion has the advantage of doing more in its use case.
That is, with my suggestion you would write

template <typename T> {
List<T>::List(...) { ... }
List<T>& List<T>::operator=(List const& other) { ... }
List<T>::iterator List<T>::find(...) { ... }
}

and with yours it would just be

template <typename T>
namespace class List {
List(...) { ... }
List& operator=(List const& other) { ... }
iterator find(...) { ... }
}

on the other hand, your suggestion would not allow for

template<class InputIterator, class Predicate> {
bool all_of(InputIterator First, InputIterator Last, Predicate Comp);
bool any_of(InputIterator First, InputIterator Last, Predicate Comp);
}

which my suggestion does allow, and I hope you would agree is useful to
have.

Also, if only one suggestion were accepted, it's not clear there would
be sufficient motivation to accept the other.

I would like to say the solution is a combination of both proposals into
one. In the combination, there are template specification scopes, and
class-namespace scopes. Thus:


template <typename T> {
namespace class List {
List(...) { ... }
List& operator=(List const& other) { ... }
iterator find(...) { ... }
}
T foo_which_may_or_may_not_be_related(T x);
}

But then, this is (a bit) more complicated than either of the individual
suggestions.

What do you think? (You = Matthew and everybody else)

Eyal

Tony V E

unread,
Apr 29, 2017, 1:14:54 PM4/29/17
to Eyal Rozenberg, d25f...@outlook.com
I don't really like "‎template specification scopes", but I'm OK with "class-namespace scopes"‎. 

Not sure why, just my gut instincts. 

Class-namespace encloses related items. 
Template specs could enclose anything. Sure, a good programmer will only use it wisely, but it is fundamentally just syntactic relationships, not semantic relationships. 
I prefer language constructs that represent semantic properties.


Sent from my BlackBerry portable Babbage Device
  Original Message  
From: Eyal Rozenberg
Sent: Saturday, April 29, 2017 12:49 PM
To: std-pr...@isocpp.org
Reply To: std-pr...@isocpp.org
Cc: d25f...@outlook.com
Subject: Re: [std-proposals] Re: Has it been proposed to allow "template <...>" to apply to multiple declarations/definitions?
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/d32aae5b-0098-e356-4629-0a5eab29f746%40technion.ac.il.

Matthew Woehlke

unread,
May 2, 2017, 10:21:11 AM5/2/17
to std-pr...@isocpp.org, Eyal Rozenberg
On 2017-04-29 12:49, Eyal Rozenberg wrote:
> Your proposal makes sense. I also think my proposal makes sense, and
> the justification is at least partially similar, i.e. "Why should a
> template specification apply to just a single
> definition/declaration?" as an example of DRY.
> [...]
> What do you think? (You = Matthew and everybody else)

The concern I have with your proposal, that I think is shared by others,
is that your scope is a *pure* token repetition; that is, the template
parameters of the scope are each *independently* applied to the items
inside the scope. Compare with P0223 where - yes, even if the
*implementation* may work similarly - the entities in the scope are
logically related.

Also, it just occurs to me, I think I can also solve your problem with
macros:

#define MY_TEMPLATE \
template <typename InputIterator, typename Predicate>

MY_TEMPLATE bool all_of(InputIterator first, Predicate comp);
MY_TEMPLATE bool any_of(InputIterator first, Predicate comp);

...which lessens the motivation. While I *can* do the same thing for
classes, it's more awkward:

#define MY_CLASS_TEMPLATE template <typename T>
#define MY_CLASS_CLASS List<T>::

MY_CLASS_TEMPLATE MY_CLASS_CLASS List(...) { ... }
MY_CLASS_TEMPLATE List<T>& MY_CLASS_CLASS operator=(...) { ... }
MY_CLASS_TEMPLATE List<T>::iterator MY_CLASS_CLASS find(...) { ... }

Unlike the previous example, this is hardly an improvement over writing
out everything the long way. Also, P0223 offers an additional benefit
that doesn't apply to your case; namely, ability to use the class name
or types that are members of the class without extra qualifiers.

--
Matthew

Eyal Rozenberg

unread,
May 2, 2017, 11:18:09 AM5/2/17
to std-pr...@isocpp.org

Well, two declarations/definitions, in the same namespace, in the same
file, appears consecutively, and with the same template parameters are
implicitly related already, I'd say. It's true that your proposal does
not imply stronger relation and mine can be construed that way; but,
well - so what? I mean, if someone wants to emphasize his consecutive
pieces of code are unrelated, then s/he just won't put them in the same
scope.

As for your macro suggestion - come on... even ignoring the general
aversion to macros, that's baroque-looking and confusing, declaring the
template parameters far away from their use (both for your example and
for mine).

Having said that, though, I'll also say I don't think I want to try and
forcefully "push" a suggestion which is met with resistance to the basic
concept. I mean, maybe that's a worthwhile thing to do, but I don't have
the 'psychological resources' to run a sort of a campaign of arguing
with people.

So, if you feel like combining suggestions - I think that would be
great; if not that's also ok and I still support your proposal (for all
the good that does you...)

Eyal

Lee Howes

unread,
May 4, 2017, 12:18:32 PM5/4/17
to std-pr...@isocpp.org
I like the class namespace proposal. I've often wished for such a thing as a clean way of separating interface from implementation in template code.

I'm a little less keen on this proposal because I share the concern that when I see:
template<typename T> {
  void foo(T param);
  void bar(T param);
}

My brain wants to assume that those Ts are the same. 

Whether that matters is open to question, and depends substantially on whether such a fact would ever be expected to be visible. It may matter with separate compilation. If I have the above in a header, then in one compilation unit:
template<typename T> {
  void foo(T param) { do something with param; }
  void bar(T param) { do something with param; }
}

something() {
foo(3);
}

It feels natural if I instantiate any one of these on an explicit type, I should be able to link against any of them. I don't think that's a reasonable assumption, but natural enough that it could lead to confusion.Using the same name but with a syntax that clearly denotes independence is a very different form implicit relation, and I think easier to explain. 


Eyal Rozenberg

unread,
May 4, 2017, 2:52:50 PM5/4/17
to std-pr...@isocpp.org
I see what you mean. I don't actually have a good comeback for this
concern. Unless... unless this would make the two functions be
instantiated together or not at all. But probably that's going a bit too
far. I dunno, I guess it's a foil then.
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/1c8_Fa3Rj44/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposal...@isocpp.org
> <mailto:std-proposal...@isocpp.org>.
> To post to this group, send email to std-pr...@isocpp.org
> <mailto:std-pr...@isocpp.org>.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAJH_FNVebzbcf-iME1unNM8MNEx2TtEnJCRtXamz769TReqYGw%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAJH_FNVebzbcf-iME1unNM8MNEx2TtEnJCRtXamz769TReqYGw%40mail.gmail.com?utm_medium=email&utm_source=footer>.
Reply all
Reply to author
Forward
0 new messages