On 2015-10-29 14:04, Nicol Bolas wrote:
> So... here's a proposal that provides mixins, inner classes, and stateless
> classes to C++. What do you think? Is this a functional idea? What cases
> did I miss?
Sorry for jumping in so late... I'm still hoping to go back and re-read
the original proposal to compare notes. Meanwhile, finally read the
proposal. Comments follow:
> Let's say that you have some container class C. It has an interface
> that works for you and your needs. But with the ranges proposal, you
> know that it doesn't really fit into that paradigm. It is
> conceptually a range, but it doesn't actually fit the range paradigm.
> And you don't want to rewrite your interface; if it's not broken,
> don't fix it.
>
> The way to resolve that today would be to create some proxy object
> PC, which internally stores a pointer/reference to a C instance. This
> object would translate the interface of C into one appropriate for
> the ranges proposal.
Do you mean like
http://permalink.gmane.org/gmane.comp.lib.qt.devel/21327 (see
qtEnumerate)? Or
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1104? :-)
Those sound like potential interesting use cases (if you happen to be
looking for concrete, real-world examples).
This brings up a related point; we'll want lifetime extension for inner
classes (i.e. retaining an inner class extends the life of a temporary
outer class that contains it).
IOW, I want to be able to do this:
Outer foo();
auto& i = foo().inner;
// ...do stuff with i
Or, equivalently, but more particularly:
for (auto i : foo().inner)
// ...
Hopefully though we'll be getting the general form of this and it can be
a moot point :-).
> In C++ as it currently stands, every object needs to have a memory
> location. And two unrelated types cannot have the same memory
> location.
Pedantic: I believe a struct and a member thereof can already have the
same address? The restriction applies to objects at the same scope.
Therefore, here:
> Stateless types effectively have to be able to break this rule. The
> memory location of a stateless member subobject can be the same
> location as the object it is a member of. And two sibling members of
> the same type may have the same location if one of them is
> stateless.
The first statement is already the case. Just the second one is new.
Is it worth talking about trivially copyability here? (Specifically,
stateless zero-sized classes should not affect trivial copyability.) Or
do you consider this sufficiently "obvious"?
> - Types that declare stateful inner class members cannot have a
> trivial default constructor, and therefore cannot be trivial types.
>
> - Stateful inner class members prevent their owning types from being
> standard layout.
There is some phrasing inversion going on here. I might consolidate
these as the first point: "...nor can such types be standard layout" (or
even just "...nor standard layout"). Or rephrase the first "Stateful
inner class members prevent their owning types from having a trivial
default constructor...".
> for each stateful inner class member, the compiler must have access
> to some data (typically a byte offset) which is used to convert this
> from Outer::Inner* to Outer*.
Question: is this necessary if a) there is exactly one NSDM of the
stateful inner class type, and b) no additional members of that type may
be added (e.g. by a derived class)?
I want to say "no", in which case we could theoretically allow these to
use a static offset also. *If* such an optimization is worthwhile, it
implies preventing additional NSDM's of the inner class type being
created. A private type would accomplish this, but I think also means
that no public member could use the type... so maybe it would be
interesting to allow e.g. "final" inner class types?
Just throwing it out there. I'm fine passing on it if it seems too
convoluted.
> Mixin Classes
> [...syntax...]
Is there a strong reason why a mixin can't just be an implicit template?
I.e.:
std::mixin class Foo { ... };
class Bar : public Foo { ... };
(This might require something like std::mixin_user to access the
typename of the final class explicitly, but that's easy.)
In case of additional template parameters, this would look like:
template <int N> std::mixin class Foo { ... };
class Bar : public Foo<3> { ... };
Naming a mixin (externally) could be done like:
typedef std::mixin<Bar> Foo<3> BarMixinFoo3;
Templated aliases would be conditionally legal:
template <int K>
using std::mixin<Bar> Foo<K>; // error
template <typename T>
using std::mixin<T> Foo<3>; // okay
template <int K> class Dog;
template <int K>
using std::mixin<Dog<K>> Foo<K>; // ???
The first is an error; the non-template-type Bar cannot have a templated
mixin. The second is always okay. The third is probably also legal, as a
declaration is not sufficient to know that Dog<K> always has mixin
Foo<K>. (Even the definition is insufficient, as specialization could
break the relation.) I believe you give a similar restriction? (I
honestly don't entirely follow that section.)
> No variables of mixin types can be declared
Just concrete instances? Or would this include pointers/references? I
believe the former is intended, but perhaps this could be worded to make
that more clear.
--
Matthew