C++ Logo

std-proposals

Advanced search

Re: Make class template parameters available externally

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Fri, 1 Nov 2019 20:30:15 -0400
On Fri, Nov 1, 2019 at 7:53 PM connor horman via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Fri, Nov 1, 2019 at 5:17 PM Dmitry via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>>
>> So, I have incorporated (all) your feedback in the proposal:
>>
>> now the feature is opt-in
>> private/protected/public keywords are used: template<public typename A,
protected int B>
>> New compiler errors are discussed: when there is a propagated template
parameter and user-defined one with the same name.
>>
>> Here is a link to the proposal (leading directly to the new opt-in
approach).
>>
>> And also there are my thoughts on the question about the upcoming class
types in non-type template parameters:
>> "Namely, do we want to have references (static constexpr int &B = _B; in
the example above), or values (static constexpr int B = _B;)?
>> No matter how smart structures it will be possible to use as template
arguments,
>> (after instantiation) they are just smartly-mangled
(16IntegralConstantIPFiRiEXadL_Z3fooIiEiRT_EEE)
>> old plain C structs, and they are entirely handled in compile-time. From
this point of view, there is
>> little point in using references. Perhaps, a safer approach would be to
understand how compile-time
>> calculations implemented in the modern compilers, in particular whether
"compile-time reference"
>> makes sense or not."
>
> references apply only to class types, and its a valid question because
the template argument itself
> is a const-lvalue if it is a class type. There might actually be a
difference as, if I remember correctly,
> and if I don’t I’m sure everyone here will get on my case, the parameter
just needs to be LiteralType
> and have Strong Structural Ordering, it does not need to have a copy or
move constructor which
> can be evaluated in a constant expression (or even have a non-deleted
copy/move constructor).

Nitpick: Ever since the splitting-up of defaulted operator<=> from
defaulted operator==, it has been the case that non-type template
parameters of class type need to have strong structural *equality*, not
necessarily strong structural *ordering*.

Presumably if this feature were adopted (and I strongly hope it's never
adopted), it wouldn't try to add new member entities to the template;
instead, it would just make the names of the existing entities visible.
That is, we'd have something like

struct Widget { bool operator==(const Widget&) const = default; };
template<public Widget W> struct Gadget {
    static_assert(std::is_same_v<decltype(W), Widget>); // C++2a:
decltype(W) is not a reference type
    const Widget *myw() { return &W; }
};
int main() {
    Gadget<Widget{}> g;
    Gadget<Widget{}> h;
    static_assert(std::is_same_v<decltype(g), decltype(h)>); // C++2a
    assert(g.myw() == h.myw()); // C++2a
    const Widget *p = &decltype(g)::W; // new proposed feature
    const Widget *q = &g.W; // new proposed feature
    assert(p == g.myw()); // Presumably g.W denotes the same entity
outside the class as inside it
    assert(q == g.myw()); // Ditto

    using WTYPE = decltype(g.W); // new proposed feature
    static_assert(std::is_same_v<WTYPE, Widget>); // Presumably
decltype(g.W) is not a reference type
}

Offhand, I would not expect `Gadget` to have a "member" `W` in any sense;
for example, I would not expect `W` to be visible to a program that used
the Reflection TS to get a list of Gadget's static data members.

> If the templates are copied when they are lvalues, how would this
proposal deal with that?

FWIW, I don't understand this question. What does "If the templates are
copied" mean?

> I’m also still questioning whether this proposal is necessary as an
opt-in feature, as we can
> effectively do this already, with a combination of using declarations,
and constexpr field declarations.

Absolutely. This proposal has no reason to exist. It does not save any
library implementor any work at all. It produces more questions than it
answers. At best, it provides an error-prone alternative way to
accomplish *something
that you can already accomplish cleanly within the existing language* (ever
since C++98). I advise the proposer to (A) drop it, but at least (B) study
the history of proposals for "keyword arguments." P0671
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0671r2.html> is a
great place to start. I suggest this because the proposal is no more or
less than "keyword arguments for template arguments instead of function
arguments," and it has all the same philosophical problems. Ville gave a
bunch of them. (For example, what happens if two declarations are in scope,
and they use two different names for the same argument? The current
proposal doesn't address this, except to say that definitions take priority
over non-definition declarations. It doesn't say how to tiebreak between
two non-definition declarations.)

Another nitpick: The current proposal suggests
    template<public template<class> class C> struct S {};
which seems like a novel placement of keywords relative to the
template-head `template<class>`. Normally, I'd expect to see
    template<template<class> public class C> struct S {};
So I'd want to see some discussion of that in the proposal.

my $.02,
–Arthur

Received on 2019-11-01 19:32:44