Topic: A strong typedef syntax idea
Author: svalorzen@gmail.com
Date: Mon, 19 Dec 2016 03:04:48 -0800 (PST)
Raw View
------=_Part_1001_2001548619.1482145488770
Content-Type: multipart/alternative;
boundary="----=_Part_1002_1207863976.1482145488771"
------=_Part_1002_1207863976.1482145488771
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
This is a stub proposal on strong typedefs, i.e. types that work in the=20
exact same way, but allow separate overloading. Other papers and proposals=
=20
exist, but I've tried a different approach that tries to mimic a more=20
inheritance-like syntax which might be more intuitive. The full text can be=
=20
found online at https://github.com/Svalorzen/CppCopyProposal.
<https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.=
=20
Thanks in advance for your comments.
Duplication and Extension of Existing Classes
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Introduction
------------
This document describes a possible approach to duplicate existing=20
functionality
while wrapping it in a new type, without the burden of inheritance and to=
=20
allow
function overloads on syntactically identical but semantically different=20
types
(also known as *strong typedef*).
The approach taken should be simple to implement and be applicable to=20
existing
code.
Optional sections are to be read as additional ideas that could be further
developed or completely ignored. They are mostly food for thought, but=20
included
for completeness.
Reasons
-------
- Scientific libraries where a type has different behaviors depending on=20
context
have currently no simple way to indicate the semantic differences. Since =
a
`typedef` does not allow multiple overloads on new typedef types - since=
=20
they
are still the "old" type - they have to resort to imperfect techniques,=
=20
such
as copying, wrapping or inheriting the needed type. Examples: coordinates=
=20
in a
plane (rectangular, polar), vectors of double (probabilities, values).
- Easier maintainability of code which is known to be the same, rather than
being copy-pasted.
- Avoiding misuse of inheritance in order to provide a copy-paste=20
alternative.
This can result in very deep hierarchies of types which should really not=
=20
have
anything to do with each other.
- Enabling users to use an existing and presumably correct type but=20
partially
extend it with context-specific methods. Examples: search for=20
"`std::vector`
inheritance" yields many results of users trying to maintain the original
interface and functionality but add one or two methods.
The functionality should have the following requirements:
- Can be applied to existing code.
- Should limit dependencies between new and old type as much as possible.
- Should allow for partial extensions of the old code.
Alternatives
------------
### Typedef / Using Directive ###
Using a type alias creates an alternative name for a single type. However,=
=20
this
leaves no space to implement overloads that are context-specific. Nor a=20
type can
be extended in a simple way while keeping the old interface intact.
### Inheritance ###
Inheritance requires redefinition of all constructors, and creates a=20
stricter
dependency between two classes than what is proposed here. Classes may be
converted to a common ancestor even though that is undesired or even=20
dangerous
in case of implicit conversions.
Inheritance may also be unwanted in order to avoid risks linked to=20
polymorphism
and freeing data structures where the base class does not have a virtual
destructor.
### Encapsulation with Manual Exposure of Needed Methods ###
This method obviously requires a great deal of code to be rewritten in=20
order to
wrap every single method that the old class was exposing.
In addition one needs to have intimate knowledge of the original interface=
=20
in
order to be able to duplicate it correctly. Template methods, rvalue=20
references,
possibly undocumented methods which are required in order to allow the=20
class to
behave in the same way as before. This heightens the bar significantly for=
=20
many
users, since they may not know correctly how to duplicate an interface and=
=20
how
to forward parameters to the old interface correctly.
The new code also must be maintained in case the old interface changes.
### Copying the Base Class ###
This can be useful, but requires all code to be duplicated, and thus
significantly increases the burden of maintaining the code. All bugs=20
discovered
in one class must be fixed in the other class too. All new features applied=
=20
to
one class must be applied to the other too.
### Macro-expansion ###
Macro expansions can be used in order to encode the interface and=20
implementation
of a given class just one time, and used multiple times to produce separate
classes.
This approach is unfortunately not applicable to existing code, and is very=
=20
hard
to extend if one wants to copy a class but add additional functionality to=
=20
it.
### Templates ###
Templates produce for each instantiation a separate type. They are=20
unfortunately
not applicable to previously existing code. For new code, they would=20
require the
creation of "fake" template parameters that would need to vary in order to
produce separate types.
In addition, class extension through templates is not possible: variations=
=20
would
need to be made through specialization, which itself requires copying=20
existing
code.
Previous Work
-------------
Strong typedefs have already been proposed for the C++ language multiple=20
times
([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf)=
,
[N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf),
[N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf),
[N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are=20
named
*opaque typedefs*, and these papers try to explore and define exactly the
behavior that such typedefs should and would have when used to create new
types. In particular, the keywords `public`, `protected` and `private` are=
=20
used
in order to create a specific relation with the original type and how is th=
e
new type allowed to be cast back to the original type or be used in its=20
place
during overloads.
This document shares many of the the same principles, for example (quoting=
=20
from
N3741):
> - Consistent with restrictions imposed on analogous relationships such as
> base classes underlying derived classes and integer types underlying=20
enums,
> an underlying type should be (1) complete and (2) not cv-quali=EF=AC=81=
ed. We=20
also do
> not require that any enum type, reference type, array type, function=20
type, or
> pointer-to-member type be allowed as an underlying type.
However, this document tries to propose a possibly more simple approach,=20
where
a new language feature is introduced with the same meaning and=20
functionality as
if the user autonomously implemented a new class him/herself, matching the
original type completely. Thus, it should result for the user more simple t=
o
understand (as it simply matches already the already understood mechanics o=
f
creating a new, unique type from nothing), and no new rules for type=20
conversion
and selection on overloads have to be created.
Syntax
------
### Simple Case ###
Syntax could look something like this:
```cpp
class Base {
public:
Base() : x(0) {}
void foo() { std::cout << "foo " << x << "\n"; }
private:
int x;
};
struct Copy : using Base {};
/* Equivalent to
struct Copy {
public:
Copy() : x(0) {}
void foo() { std::cout << "foo " << x << "\n"; }
private:
int x;
};
*/
```
One cannot copy a class and inherit at the same time. If such a class is=20
needed
one would need to create it by hand with the desided functionality and
inheriting from the desired classes, as it would be done normally.
All method implementations would be the same. The copied class would inheri=
t
from the same classes its base class inherits from. All constructors would=
=20
work
in the same way.
### Adding New Functionality ###
Ideally one could specify additional methods, separate from that of Base,=
=20
to add
upon the existing functionality.
```cpp
struct Base {
void foo() { std::cout << "foo\n"; }
};
struct Derived : public Base {};
struct Copy : using Base {
void bar() { std::cout << "bar\n"; }
};
struct CopyDerived : using Derived {};
/* Equivalent to
struct Copy {
void foo() { std::cout << "foo\n"; }
void bar() { std::cout << "bar\n"; }
};
struct CopyDerived : public Base {};
*/
```
Only new methods need to be implemented for that class.
#### Interfacing with the Original Class ####
In order to interface with the original class, simple conversion operators=
=20
can
be added by the user explicitly at-will, in order to obtain the desired
interface. Note that if more types with this kind of compatibility were=20
needed,
one would only need to implement them once, since copying the produced type
would copy the new, more compatible interface with it.
```cpp
struct Base {
public:
int x;
private:
double y;
};
struct Copy : using Base {
operator Base() { return Base{x, y}; }
};
```
`reinterpret_cast` may also be used to convert back to the original class,
limited by the tool's already existing rules.
In general the usual rules of `reinterpret_cast` apply to the copied classe=
s
with respect to their general classes, exactly as if the copied class had=
=20
been
implemented by hand.
### Overloads ###
Duplicating an existing class should allow for new overloads on the new=20
type,
and no ambiguity between the copied class, the old class and other copied
classes.
```cpp
class Position : using std::pair<double, double> {};
class Distance : using std::pair<double, double> {};
Position operator+(const Position & p, const Distance & d) {
return Position(p.first + d.first, p.second + d.second);
}
Distance operator+(const Distance & lhs, const Distance & rhs) {
return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
}
// ...
Position p(1, 1);
Distance d(1, 1);
p + d; // OK
d + d; // OK
p + p; // Error
```
### Templated Class Copy ###
The user might want to create a single templatized copy interface, and use=
=20
it
multiple times. For example, one might want multiple copied classes which=
=20
can
convert to their original. This could be done as follows:
```cpp
struct A { int x; };
template <typename T>
struct TemplatizedCopy : using T {
static_assert(std::is_standard_layout<T>::value,
"Can't use this with a non-standard-layout class");
operator T&() { return *reinterpret_cast<T*>(this); }
};
// Could be used either via normal typedefs
using Copy1 =3D TemplatizedCopy<A>;
// Or via copy, depending on requirements.
struct Copy2 : using TemplatizedCopy<A> {};
```
### Copying Template Classes ###
Since the construct is similar to inheritance, the syntax for creating=20
aliases
of templated classes could be the same:
```cpp
template <typename T>
struct A {};
template <typename T>
struct B : using A<T> {};
B<int> b;
```
The copied class must have the same number or less of template parameters=
=20
than
the base class. Partial or full specializations of the base class can be=20
allowed:
```cpp
template <typename T, typename U>
struct A {};
template <typename T>
struct B : using A<T, double> {};
B<int> b;
```
When the base class has partial specializations, only those who apply are=
=20
copied
to the copied class.
```cpp
template <typename T, typename U>
struct A { T t; U u; };
template <typename U>
struct A<double, U> { double y; U u; };
template <typename T>
struct A<T, int> { T t; char z; };
template <typename T>
struct B : using A<T, double> {};
/* Equivalent to
template <typename T>
struct B { T t; double u; };
template <>
struct B<double> { double y; double u; };
*/
```
The copied class can add additional specializations. Or specializations for=
=20
a
given class can copy another.
```cpp
template <typename T>
struct A { int x; };
struct B { char c; };
template <typename T>
struct C : using A<T> {};
template <>
struct C<double> : using B {};
template <>
struct A<int> : using C<double> {};
/* Equivalent to
template<>
struct A<int> { char c; };
template <typename T>
struct C { int x; };
template <>
struct C<double> { char c; };
*/
```
### Copying Multiple Dependent Classes ###
Copying multiple classes using the simple syntax we have described can be
impossible if those classes depend on one another. This is because each cop=
y
would depend on the originals, rather than on the copied classes. A=20
possible way
to specify such dependencies could be:
```cpp
struct A;
struct B {
A * a;
};
struct A {
B b;
};
struct C;
struct D : using B {
using class C =3D A;
};
struct C : using A {
using class D =3D B;
};
/* Equivalent to
struct C;
struct D {
C * a;
};
struct C {
D b;
};
*/
```
`using class` has been used in order to disambiguate it from normal `using`
alias directive. `using class` is only valid when the left hand side has=20
been
defined as a copy of the right hand side.
In case of a template base class using a template second class, one could
specify different copies for certain specializations;
```cpp
template <typename T>
struct A {};
template <typename T>
struct B {
A<T> a;
};
template <typename T>
struct C : using A<T> {};
```
### Substituting Existing Functionality (Optional) ###
Ideally one may want to use most of an implementation for another class, bu=
t
vary a certain number of methods. In this case, if `Copy` contains a member
function that already exists in `Base`, then that implementation is=20
substituted
in `Copy`. This may or may not be allowed for attributes.
```cpp
struct Base {
void foo() { std::cout << "foo\n"; }
void bar() { std::cout << "bar\n"; }
};
struct Copy : using Base {
void foo() { std::cout << "baz\n"; }
};
/* Equivalent to
struct Copy {
void foo() { std::cout << "baz\n"; }
void bar() { std::cout << "bar\n"; }
};
*/
```
A side effect of this is that it could allow for some type of "interface",=
=20
where
some base class could be defined as:
```cpp
struct Base {
Base() =3D delete;
void foo();
void bar();
};
struct Copy1 : using Base {
Copy1() =3D default;
void baz();
void foo() =3D delete;
};
/* Equivalent to
struct Copy1 {
Copy1() =3D default;
void bar();
void baz();
};
*/
struct Copy2 : using Base {
Copy2(int);
void abc();
};
/*
Equivalent to
struct Copy2 {
Copy2(int);
void foo();
void bar();
void abc();
};
*/
```
This feature could however present problems when the members changed also=
=20
alter
behavior and/or variable types of non-modified member and non-member=20
functions,
since the new behavior could be either erroneous or ambiguous.
### Copying and Extending Primitive Types (Optional) ###
The same syntax could be used in order to extend primitive types. Using the
extension that allows the modification of the copied types, this could=20
allow for
creation of numeric types where some operations are disabled as needed.
```cpp
struct Id : using int {
Id operator+(Id, Id) =3D delete;
Id operator*(Id, Id) =3D delete;
// Non-explicitly deleted operators keep their validity
// Defining new operators with the old type can allow interoperativity
Id operator+(Id, int);
// We can convert the copied type to the old one.
operator int() { return (*this) * 2; }
};
/* Equivalent to
class Id final {
public:
Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
Id operator+(Id, int);
operator int() { return v_ * 2; }
private:
int v_;
};
*/
```
Note that when copying from a primitive types inheritance is forbidden as=
=20
the
generated copy is `final` (although it is allowed to keep copying the newly
created class).
### STL Traits (Optional) ###
Traits could be included in the standard library in order to determine=20
whether a
class is a copy of another, or if it has been derived from a copy
(copies/inheritances could be nested arbitrarily).
```cpp
struct Base {};
struct Copy : using Base {};
static_assert(std::is_copy<Copy, Base>::value);
struct ChildCopy : public Copy {};
struct CopyChildCopy : using ChildCopy {};
static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
```
Compatibility
-------------
As the syntax is new, no old code would be affected.
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/fd8eda2b-182f-4e32-8fda-c7f728e22fa2%40isocpp.or=
g.
------=_Part_1002_1207863976.1482145488771
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">This is a stub proposal on strong typedefs, i.e. types tha=
t work in the exact same way, but allow separate overloading. Other papers =
and proposals exist, but I've tried a different approach that tries to =
mimic a more inheritance-like syntax which might be more intuitive. The ful=
l text can be found online at <a href=3D"https://github.com/Svalorzen/CppCo=
pyProposal">https://github.com/Svalorzen/CppCopyProposal.<br><br></a>I'=
m copying the text below. Thanks in advance for your comments.<br><br><span=
style=3D"font-family: courier new,monospace;">Duplication and Extension of=
Existing Classes<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D<br><br>Introduction<br>------------<br><br>This document describes a=
possible approach to duplicate existing functionality<br>while wrapping it=
in a new type, without the burden of inheritance and to allow<br>function =
overloads on syntactically identical but semantically different types<br>(a=
lso known as *strong typedef*).<br><br>The approach taken should be simple =
to implement and be applicable to existing<br>code.<br><br>Optional section=
s are to be read as additional ideas that could be further<br>developed or =
completely ignored. They are mostly food for thought, but included<br>for c=
ompleteness.<br><br>Reasons<br>-------<br><br>- Scientific libraries where =
a type has different behaviors depending on context<br>=C2=A0 have currentl=
y no simple way to indicate the semantic differences. Since a<br>=C2=A0 `ty=
pedef` does not allow multiple overloads on new typedef types - since they<=
br>=C2=A0 are still the "old" type - they have to resort to imper=
fect techniques, such<br>=C2=A0 as copying, wrapping or inheriting the need=
ed type. Examples: coordinates in a<br>=C2=A0 plane (rectangular, polar), v=
ectors of double (probabilities, values).<br>- Easier maintainability of co=
de which is known to be the same, rather than<br>=C2=A0 being copy-pasted.<=
br>- Avoiding misuse of inheritance in order to provide a copy-paste altern=
ative.<br>=C2=A0 This can result in very deep hierarchies of types which sh=
ould really not have<br>=C2=A0 anything to do with each other.<br>- Enablin=
g users to use an existing and presumably correct type but partially<br>=C2=
=A0 extend it with context-specific methods. Examples: search for "`st=
d::vector`<br>=C2=A0 inheritance" yields many results of users trying =
to maintain the original<br>=C2=A0 interface and functionality but add one =
or two methods.<br><br>The functionality should have the following requirem=
ents:<br><br>- Can be applied to existing code.<br>- Should limit dependenc=
ies between new and old type as much as possible.<br>- Should allow for par=
tial extensions of the old code.<br><br>Alternatives<br>------------<br><br=
>### Typedef / Using Directive ###<br><br>Using a type alias creates an alt=
ernative name for a single type. However, this<br>leaves no space to implem=
ent overloads that are context-specific. Nor a type can<br>be extended in a=
simple way while keeping the old interface intact.<br><br>### Inheritance =
###<br><br>Inheritance requires redefinition of all constructors, and creat=
es a stricter<br>dependency between two classes than what is proposed here.=
Classes may be<br>converted to a common ancestor even though that is undes=
ired or even dangerous<br>in case of implicit conversions.<br><br>Inheritan=
ce may also be unwanted in order to avoid risks linked to polymorphism<br>a=
nd freeing data structures where the base class does not have a virtual<br>=
destructor.<br><br>### Encapsulation with Manual Exposure of Needed Methods=
###<br><br>This method obviously requires a great deal of code to be rewri=
tten in order to<br>wrap every single method that the old class was exposin=
g.<br><br>In addition one needs to have intimate knowledge of the original =
interface in<br>order to be able to duplicate it correctly. Template method=
s, rvalue references,<br>possibly undocumented methods which are required i=
n order to allow the class to<br>behave in the same way as before. This hei=
ghtens the bar significantly for many<br>users, since they may not know cor=
rectly how to duplicate an interface and how<br>to forward parameters to th=
e old interface correctly.<br><br>The new code also must be maintained in c=
ase the old interface changes.<br><br>### Copying the Base Class ###<br><br=
>This can be useful, but requires all code to be duplicated, and thus<br>si=
gnificantly increases the burden of maintaining the code. All bugs discover=
ed<br>in one class must be fixed in the other class too. All new features a=
pplied to<br>one class must be applied to the other too.<br><br>### Macro-e=
xpansion ###<br><br>Macro expansions can be used in order to encode the int=
erface and implementation<br>of a given class just one time, and used multi=
ple times to produce separate<br>classes.<br><br>This approach is unfortuna=
tely not applicable to existing code, and is very hard<br>to extend if one =
wants to copy a class but add additional functionality to it.<br><br>### Te=
mplates ###<br><br>Templates produce for each instantiation a separate type=
.. They are unfortunately<br>not applicable to previously existing code. For=
new code, they would require the<br>creation of "fake" template =
parameters that would need to vary in order to<br>produce separate types.<b=
r><br>In addition, class extension through templates is not possible: varia=
tions would<br>need to be made through specialization, which itself require=
s copying existing<br>code.<br><br>Previous Work<br>-------------<br><br>St=
rong typedefs have already been proposed for the C++ language multiple time=
s<br>([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706=
..pdf),<br>[N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n=
1891.pdf),<br>[N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/20=
13/n3515.pdf),<br>[N3741](https://isocpp.org/files/papers/n3741.pdf)). Thes=
e typedefs are named<br>*opaque typedefs*, and these papers try to explore =
and define exactly the<br>behavior that such typedefs should and would have=
when used to create new<br>types. In particular, the keywords `public`, `p=
rotected` and `private` are used<br>in order to create a specific relation =
with the original type and how is the<br>new type allowed to be cast back t=
o the original type or be used in its place<br>during overloads.<br><br>Thi=
s document shares many of the the same principles, for example (quoting fro=
m<br>N3741):<br><br>> - Consistent with restrictions imposed on analogou=
s relationships such as<br>>=C2=A0=C2=A0 base classes underlying derived=
classes and integer types underlying enums,<br>>=C2=A0=C2=A0 an underly=
ing type should be (1) complete and (2) not cv-quali=EF=AC=81ed. We also do=
<br>>=C2=A0=C2=A0 not require that any enum type, reference type, array =
type, function type, or<br>>=C2=A0=C2=A0 pointer-to-member type be allow=
ed as an underlying type.<br><br>However, this document tries to propose a =
possibly more simple approach, where<br>a new language feature is introduce=
d with the same meaning and functionality as<br>if the user autonomously im=
plemented a new class him/herself, matching the<br>original type completely=
.. Thus, it should result for the user more simple to<br>understand (as it s=
imply matches already the already understood mechanics of<br>creating a new=
, unique type from nothing), and no new rules for type conversion<br>and se=
lection on overloads have to be created.<br><br>Syntax<br>------<br><br>###=
Simple Case ###<br><br>Syntax could look something like this:<br><br>```cp=
p<br>class Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 Base() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 void foo() { std::cout << "foo " << x <<=
"\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>struct Copy : using Base {};<br><=
br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo &q=
uot; << x << "\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<b=
r>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<=
br><br>One cannot copy a class and inherit at the same time. If such a clas=
s is needed<br>one would need to create it by hand with the desided functio=
nality and<br>inheriting from the desired classes, as it would be done norm=
ally.<br><br>All method implementations would be the same. The copied class=
would inherit<br>from the same classes its base class inherits from. All c=
onstructors would work<br>in the same way.<br><br>### Adding New Functional=
ity ###<br><br>Ideally one could specify additional methods, separate from =
that of Base, to add<br>upon the existing functionality.<br><br>```cpp<br>s=
truct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "fo=
o\n"; }<br>};<br><br>struct Derived : public Base {};<br><br>struct Co=
py : using Base {<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << &qu=
ot;bar\n"; }<br>};<br><br>struct CopyDerived : using Derived {};<br><b=
r>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { =
std::cout << "foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { =
std::cout << "bar\n"; }<br>};<br><br>struct CopyDerived : p=
ublic Base {};<br><br>*/<br>```<br><br>Only new methods need to be implemen=
ted for that class.<br><br>#### Interfacing with the Original Class ####<br=
><br>In order to interface with the original class, simple conversion opera=
tors can<br>be added by the user explicitly at-will, in order to obtain the=
desired<br>interface. Note that if more types with this kind of compatibil=
ity were needed,<br>one would only need to implement them once, since copyi=
ng the produced type<br>would copy the new, more compatible interface with =
it.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 priva=
te:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>st=
ruct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 operator Base() { return Bas=
e{x, y}; }<br>};<br>```<br><br>`reinterpret_cast` may also be used to conve=
rt back to the original class,<br>limited by the tool's already existin=
g rules.<br><br>In general the usual rules of `reinterpret_cast` apply to t=
he copied classes<br>with respect to their general classes, exactly as if t=
he copied class had been<br>implemented by hand.<br><br>### Overloads ###<b=
r><br>Duplicating an existing class should allow for new overloads on the n=
ew type,<br>and no ambiguity between the copied class, the old class and ot=
her copied<br>classes.<br><br>```cpp<br>class Position : using std::pair<=
;double, double> {};<br>class Distance : using std::pair<double, doub=
le> {};<br><br>Position operator+(const Position & p, const Distance=
& d) {<br>=C2=A0=C2=A0=C2=A0 return Position(p.first + d.first, p.seco=
nd + d.second);<br>}<br><br>Distance operator+(const Distance & lhs, co=
nst Distance & rhs) {<br>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first +=
rhs.first, lhs.second + rhs.second);<br>}<br><br>// ...<br><br>Position p(=
1, 1);<br>Distance d(1, 1);<br><br>p + d; // OK<br>d + d; // OK<br>p + p; /=
/ Error<br>```<br><br>### Templated Class Copy ###<br><br>The user might wa=
nt to create a single templatized copy interface, and use it<br>multiple ti=
mes. For example, one might want multiple copied classes which can<br>conve=
rt to their original. This could be done as follows:<br><br>```cpp<br>struc=
t A { int x; };<br><br>template <typename T><br>struct TemplatizedCop=
y : using T {<br>=C2=A0=C2=A0=C2=A0 static_assert(std::is_standard_layout&l=
t;T>::value,<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this w=
ith a non-standard-layout class");<br><br>=C2=A0=C2=A0=C2=A0 operator =
T&() { return *reinterpret_cast<T*>(this); }<br>};<br><br>// Coul=
d be used either via normal typedefs<br>using Copy1 =3D TemplatizedCopy<=
A>;<br><br>// Or via copy, depending on requirements.<br>struct Copy2 : =
using TemplatizedCopy<A> {};<br>```<br><br>### Copying Template Class=
es ###<br><br>Since the construct is similar to inheritance, the syntax for=
creating aliases<br>of templated classes could be the same:<br><br>```cpp<=
br>template <typename T><br>struct A {};<br><br>template <typename=
T><br>struct B : using A<T> {};<br><br>B<int> b;<br>```<br>=
<br>The copied class must have the same number or less of template paramete=
rs than<br>the base class. Partial or full specializations of the base clas=
s can be allowed:<br><br>```cpp<br>template <typename T, typename U><=
br>struct A {};<br><br>template <typename T><br>struct B : using A<=
;T, double> {};<br><br>B<int> b;<br>```<br><br>When the base class=
has partial specializations, only those who apply are copied<br>to the cop=
ied class.<br><br>```cpp<br>template <typename T, typename U><br>stru=
ct A { T t; U u; };<br><br>template <typename U><br>struct A<doubl=
e, U> { double y; U u; };<br><br>template <typename T><br>struct A=
<T, int> { T t; char z; };<br><br>template <typename T><br>stru=
ct B : using A<T, double> {};<br><br>/* Equivalent to<br><br>template=
<typename T><br>struct B { T t; double u; };<br><br>template <>=
;<br>struct B<double> { double y; double u; };<br><br>*/<br>```<br><b=
r>The copied class can add additional specializations. Or specializations f=
or a<br>given class can copy another.<br><br>```cpp<br>template <typenam=
e T><br>struct A { int x; };<br><br>struct B { char c; };<br><br>templat=
e <typename T><br>struct C : using A<T> {};<br><br>template <=
;><br>struct C<double> : using B {};<br><br>template <><br>s=
truct A<int> : using C<double> {};<br><br>/* Equivalent to<br><=
br>template<><br>struct A<int> { char c; };<br><br>template <=
;typename T><br>struct C { int x; };<br><br>template <><br>struct =
C<double> { char c; };<br><br>*/<br>```<br><br>### Copying Multiple D=
ependent Classes ###<br><br>Copying multiple classes using the simple synta=
x we have described can be<br>impossible if those classes depend on one ano=
ther. This is because each copy<br>would depend on the originals, rather th=
an on the copied classes. A possible way<br>to specify such dependencies co=
uld be:<br><br>```cpp<br>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 =
A * a;<br>};<br><br>struct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>stru=
ct C;<br><br>struct D : using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A=
;<br>};<br><br>struct C : using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D=
B;<br>};<br><br>/* Equivalent to<br><br>struct C;<br><br>struct D {<br>=C2=
=A0=C2=A0=C2=A0 C * a;<br>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<b=
r>};<br><br>*/<br>```<br><br>`using class` has been used in order to disamb=
iguate it from normal `using`<br>alias directive. `using class` is only val=
id when the left hand side has been<br>defined as a copy of the right hand =
side.<br><br>In case of a template base class using a template second class=
, one could<br>specify different copies for certain specializations;<br><br=
>```cpp<br>template <typename T><br>struct A {};<br><br>template <=
typename T><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><=
br>template <typename T><br>struct C : using A<T> {};<br><br>``=
`<br><br>### Substituting Existing Functionality (Optional) ###<br><br>Idea=
lly one may want to use most of an implementation for another class, but<br=
>vary a certain number of methods. In this case, if `Copy` contains a membe=
r<br>function that already exists in `Base`, then that implementation is su=
bstituted<br>in `Copy`. This may or may not be allowed for attributes.<br><=
br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout <=
;< "foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout <=
;< "bar\n"; }<br>};<br><br>struct Copy : using Base {<br>=C2=
=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n"; }<br>};<=
br><br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo=
() { std::cout << "baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar=
() { std::cout << "bar\n"; }<br>};<br><br>*/<br>```<br><br>=
A side effect of this is that it could allow for some type of "interfa=
ce", where<br>some base class could be defined as:<br><br>```cpp<br>st=
ruct Base {<br>=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 =
void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : u=
sing Base {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=
=A0 void baz();<br>=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/=
* Equivalent to<br><br>struct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D def=
ault;<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<b=
r>};<br><br>*/<br><br>struct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Cop=
y2(int);<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalen=
t to<br><br>struct Copy2 {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=
=A0=C2=A0 void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=
=A0 void abc();<br>};<br><br>*/<br>```<br><br>This feature could however pr=
esent problems when the members changed also alter<br>behavior and/or varia=
ble types of non-modified member and non-member functions,<br>since the new=
behavior could be either erroneous or ambiguous.<br><br>### Copying and Ex=
tending Primitive Types (Optional) ###<br><br>The same syntax could be used=
in order to extend primitive types. Using the<br>extension that allows the=
modification of the copied types, this could allow for<br>creation of nume=
ric types where some operations are disabled as needed.<br><br>```cpp<br>st=
ruct Id : using int {<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete=
;<br>=C2=A0=C2=A0=C2=A0 Id operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=
=A0 // Non-explicitly deleted operators keep their validity<br><br>=C2=A0=
=C2=A0=C2=A0 // Defining new operators with the old type can allow interope=
rativity<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=
// We can convert the copied type to the old one.<br>=C2=A0=C2=A0=C2=A0 op=
erator int() { return (*this) * 2; }<br>};<br><br>/* Equivalent to<br><br>c=
lass Id final {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_=
}; }<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id =
rhs) { return Id{lhs.v_ - rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 operator int() { return v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<b=
r><br>Note that when copying from a primitive types inheritance is forbidde=
n as the<br>generated copy is `final` (although it is allowed to keep copyi=
ng the newly<br>created class).<br><br>### STL Traits (Optional) ###<br><br=
>Traits could be included in the standard library in order to determine whe=
ther a<br>class is a copy of another, or if it has been derived from a copy=
<br>(copies/inheritances could be nested arbitrarily).<br><br>```cpp<br>str=
uct Base {};<br><br>struct Copy : using Base {};<br><br>static_assert(std::=
is_copy<Copy, Base>::value);<br><br>struct ChildCopy : public Copy {}=
;<br><br>struct CopyChildCopy : using ChildCopy {};<br><br>static_assert(st=
d::is_copy_base_of<Base, CopyChildCopy>::value);<br>```<br><br>Compat=
ibility<br>-------------<br><br>As the syntax is new, no old code would be =
affected.<br></span><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/fd8eda2b-182f-4e32-8fda-c7f728e22fa2%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/fd8eda2b-182f-4e32-8fda-c7f728e22fa2=
%40isocpp.org</a>.<br />
------=_Part_1002_1207863976.1482145488771--
------=_Part_1001_2001548619.1482145488770--
.
Author: "S.B." <i.and.my.little.friends@gmail.com>
Date: Tue, 20 Dec 2016 09:18:17 -0800 (PST)
Raw View
------=_Part_1735_1433328500.1482254298071
Content-Type: multipart/alternative;
boundary="----=_Part_1736_1306221838.1482254298072"
------=_Part_1736_1306221838.1482254298072
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
According to your proposal, what should B::Self be in the following example=
?
struct A {
using Self =3D A;
};
struct B : using A {};
According to your proposal, how should the copy assignement operator of B=
=20
look like?
struct A {
using Self =3D A;
A& operator=3D(const Self&) { return *this; }
};
struct B : using A {};
On Monday, December 19, 2016 at 7:04:48 PM UTC+8, sval...@gmail.com wrote:
>
> This is a stub proposal on strong typedefs, i.e. types that work in the=
=20
> exact same way, but allow separate overloading. Other papers and proposal=
s=20
> exist, but I've tried a different approach that tries to mimic a more=20
> inheritance-like syntax which might be more intuitive. The full text can =
be=20
> found online at https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.=
=20
> Thanks in advance for your comments.
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing=20
> functionality
> while wrapping it in a new type, without the burden of inheritance and to=
=20
> allow
> function overloads on syntactically identical but semantically different=
=20
> types
> (also known as *strong typedef*).
>
> The approach taken should be simple to implement and be applicable to=20
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but=20
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending on=
=20
> context
> have currently no simple way to indicate the semantic differences. Sinc=
e=20
> a
> `typedef` does not allow multiple overloads on new typedef types - sinc=
e=20
> they
> are still the "old" type - they have to resort to imperfect techniques,=
=20
> such
> as copying, wrapping or inheriting the needed type. Examples:=20
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather th=
an
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste=20
> alternative.
> This can result in very deep hierarchies of types which should really=
=20
> not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but=20
> partially
> extend it with context-specific methods. Examples: search for=20
> "`std::vector`
> inheritance" yields many results of users trying to maintain the origin=
al
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type. However=
,=20
> this
> leaves no space to implement overloads that are context-specific. Nor a=
=20
> type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a=20
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even=20
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to=20
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in=20
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original interfac=
e=20
> in
> order to be able to duplicate it correctly. Template methods, rvalue=20
> references,
> possibly undocumented methods which are required in order to allow the=20
> class to
> behave in the same way as before. This heightens the bar significantly fo=
r=20
> many
> users, since they may not know correctly how to duplicate an interface an=
d=20
> how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs=20
> discovered
> in one class must be fixed in the other class too. All new features=20
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and=20
> implementation
> of a given class just one time, and used multiple times to produce separa=
te
> classes.
>
> This approach is unfortunately not applicable to existing code, and is=20
> very hard
> to extend if one wants to copy a class but add additional functionality t=
o=20
> it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are=20
> unfortunately
> not applicable to previously existing code. For new code, they would=20
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible: variation=
s=20
> would
> need to be made through specialization, which itself requires copying=20
> existing
> code.
>
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language multiple=
=20
> times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f
> ),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf
> ),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
> ),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are=
=20
> named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private` ar=
e=20
> used
> in order to create a specific relation with the original type and how is=
=20
> the
> new type allowed to be cast back to the original type or be used in its=
=20
> place
> during overloads.
>
> This document shares many of the the same principles, for example (quotin=
g=20
> from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships such =
as
> > base classes underlying derived classes and integer types underlying=
=20
> enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We=20
> also do
> > not require that any enum type, reference type, array type, function=
=20
> type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple approach,=
=20
> where
> a new language feature is introduced with the same meaning and=20
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more simple=
=20
> to
> understand (as it simply matches already the already understood mechanics=
=20
> of
> creating a new, unique type from nothing), and no new rules for type=20
> conversion
> and selection on overloads have to be created.
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class is=
=20
> needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would=20
> inherit
> from the same classes its base class inherits from. All constructors woul=
d=20
> work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of Base,=
=20
> to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion operator=
s=20
> can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility were=
=20
> needed,
> one would only need to implement them once, since copying the produced ty=
pe
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
>
> In general the usual rules of `reinterpret_cast` apply to the copied=20
> classes
> with respect to their general classes, exactly as if the copied class had=
=20
> been
> implemented by hand.
>
> ### Overloads ###
>
> Duplicating an existing class should allow for new overloads on the new=
=20
> type,
> and no ambiguity between the copied class, the old class and other copied
> classes.
>
> ```cpp
> class Position : using std::pair<double, double> {};
> class Distance : using std::pair<double, double> {};
>
> Position operator+(const Position & p, const Distance & d) {
> return Position(p.first + d.first, p.second + d.second);
> }
>
> Distance operator+(const Distance & lhs, const Distance & rhs) {
> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
> }
>
> // ...
>
> Position p(1, 1);
> Distance d(1, 1);
>
> p + d; // OK
> d + d; // OK
> p + p; // Error
> ```
>
> ### Templated Class Copy ###
>
> The user might want to create a single templatized copy interface, and us=
e=20
> it
> multiple times. For example, one might want multiple copied classes which=
=20
> can
> convert to their original. This could be done as follows:
>
> ```cpp
> struct A { int x; };
>
> template <typename T>
> struct TemplatizedCopy : using T {
> static_assert(std::is_standard_layout<T>::value,
> "Can't use this with a non-standard-layout class");
>
> operator T&() { return *reinterpret_cast<T*>(this); }
> };
>
> // Could be used either via normal typedefs
> using Copy1 =3D TemplatizedCopy<A>;
>
> // Or via copy, depending on requirements.
> struct Copy2 : using TemplatizedCopy<A> {};
> ```
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating=20
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template parameters=
=20
> than
> the base class. Partial or full specializations of the base class can be=
=20
> allowed:
>
> ```cpp
> template <typename T, typename U>
> struct A {};
>
> template <typename T>
> struct B : using A<T, double> {};
>
> B<int> b;
> ```
>
> When the base class has partial specializations, only those who apply are=
=20
> copied
> to the copied class.
>
> ```cpp
> template <typename T, typename U>
> struct A { T t; U u; };
>
> template <typename U>
> struct A<double, U> { double y; U u; };
>
> template <typename T>
> struct A<T, int> { T t; char z; };
>
> template <typename T>
> struct B : using A<T, double> {};
>
> /* Equivalent to
>
> template <typename T>
> struct B { T t; double u; };
>
> template <>
> struct B<double> { double y; double u; };
>
> */
> ```
>
> The copied class can add additional specializations. Or specializations=
=20
> for a
> given class can copy another.
>
> ```cpp
> template <typename T>
> struct A { int x; };
>
> struct B { char c; };
>
> template <typename T>
> struct C : using A<T> {};
>
> template <>
> struct C<double> : using B {};
>
> template <>
> struct A<int> : using C<double> {};
>
> /* Equivalent to
>
> template<>
> struct A<int> { char c; };
>
> template <typename T>
> struct C { int x; };
>
> template <>
> struct C<double> { char c; };
>
> */
> ```
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because each=
=20
> copy
> would depend on the originals, rather than on the copied classes. A=20
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A;
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal `usin=
g`
> alias directive. `using class` is only valid when the left hand side has=
=20
> been
> defined as a copy of the right hand side.
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
> ### Substituting Existing Functionality (Optional) ###
>
> Ideally one may want to use most of an implementation for another class,=
=20
> but
> vary a certain number of methods. In this case, if `Copy` contains a memb=
er
> function that already exists in `Base`, then that implementation is=20
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of "interface"=
,=20
> where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed also=
=20
> alter
> behavior and/or variable types of non-modified member and non-member=20
> functions,
> since the new behavior could be either erroneous or ambiguous.
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types. Using t=
he
> extension that allows the modification of the copied types, this could=20
> allow for
> creation of numeric types where some operations are disabled as needed.
>
> ```cpp
> struct Id : using int {
> Id operator+(Id, Id) =3D delete;
> Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
> // Defining new operators with the old type can allow interoperativit=
y
> Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden as=
=20
> the
> generated copy is `final` (although it is allowed to keep copying the new=
ly
> created class).
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine=20
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
> Compatibility
> -------------
>
> As the syntax is new, no old code would be affected.
>
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/bd7f888f-d841-4f73-a148-dbb08f59faf0%40isocpp.or=
g.
------=_Part_1736_1306221838.1482254298072
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">According to your proposal, what should <span style=3D"fon=
t-family: courier new,monospace;">B::Self</span> be in the following exampl=
e?<br><div style=3D"background-color: rgb(250, 250, 250); border-color: rgb=
(187, 187, 187); border-style: solid; border-width: 1px; overflow-wrap: bre=
ak-word;" class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"s=
ubprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">st=
ruct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> A </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">using</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Self</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> A</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> B </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">using</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> A </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{};</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span></div></code></div><br><br>According to your pr=
oposal, how should the copy assignement operator of B look like?<br><div st=
yle=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 18=
7); border-style: solid; border-width: 1px; overflow-wrap: break-word;" cla=
ss=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> A </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">using</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
06;" class=3D"styled-by-prettify">Self</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> A</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 =C2=A0 A</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">&</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">operator<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D(</span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #606;" class=3D"styled-by-prettify">Self</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&)</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">return</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">*</spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">this</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br><br></span><span style=3D"color: #008;" class=3D"styled=
-by-prettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> B </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">using</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> A </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">{};</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>=
<br><br><br>On Monday, December 19, 2016 at 7:04:48 PM UTC+8, sval...@gmail=
..com wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Th=
is is a stub proposal on strong typedefs, i.e. types that work in the exact=
same way, but allow separate overloading. Other papers and proposals exist=
, but I've tried a different approach that tries to mimic a more inheri=
tance-like syntax which might be more intuitive. The full text can be found=
online at <a href=3D"https://github.com/Svalorzen/CppCopyProposal" target=
=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'https://www.go=
ogle.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCopyProposal\x2=
6sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQw';ret=
urn true;" onclick=3D"this.href=3D'https://www.google.com/url?q\x3dhttp=
s%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCopyProposal\x26sa\x3dD\x26sntz\x3d1\=
x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQw';return true;">https://git=
hub.com/Svalorzen/<wbr>CppCopyProposal.<br><br></a>I'm copying the text=
below. Thanks in advance for your comments.<br><br><span style=3D"font-fam=
ily:courier new,monospace">Duplication and Extension of Existing Classes<br=
>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br=
>Introduction<br>------------<br><br>This document describes a possible app=
roach to duplicate existing functionality<br>while wrapping it in a new typ=
e, without the burden of inheritance and to allow<br>function overloads on =
syntactically identical but semantically different types<br>(also known as =
*strong typedef*).<br><br>The approach taken should be simple to implement =
and be applicable to existing<br>code.<br><br>Optional sections are to be r=
ead as additional ideas that could be further<br>developed or completely ig=
nored. They are mostly food for thought, but included<br>for completeness.<=
br><br>Reasons<br>-------<br><br>- Scientific libraries where a type has di=
fferent behaviors depending on context<br>=C2=A0 have currently no simple w=
ay to indicate the semantic differences. Since a<br>=C2=A0 `typedef` does n=
ot allow multiple overloads on new typedef types - since they<br>=C2=A0 are=
still the "old" type - they have to resort to imperfect techniqu=
es, such<br>=C2=A0 as copying, wrapping or inheriting the needed type. Exam=
ples: coordinates in a<br>=C2=A0 plane (rectangular, polar), vectors of dou=
ble (probabilities, values).<br>- Easier maintainability of code which is k=
nown to be the same, rather than<br>=C2=A0 being copy-pasted.<br>- Avoiding=
misuse of inheritance in order to provide a copy-paste alternative.<br>=C2=
=A0 This can result in very deep hierarchies of types which should really n=
ot have<br>=C2=A0 anything to do with each other.<br>- Enabling users to us=
e an existing and presumably correct type but partially<br>=C2=A0 extend it=
with context-specific methods. Examples: search for "`std::vector`<br=
>=C2=A0 inheritance" yields many results of users trying to maintain t=
he original<br>=C2=A0 interface and functionality but add one or two method=
s.<br><br>The functionality should have the following requirements:<br><br>=
- Can be applied to existing code.<br>- Should limit dependencies between n=
ew and old type as much as possible.<br>- Should allow for partial extensio=
ns of the old code.<br><br>Alternatives<br>------------<br><br>### Typedef =
/ Using Directive ###<br><br>Using a type alias creates an alternative name=
for a single type. However, this<br>leaves no space to implement overloads=
that are context-specific. Nor a type can<br>be extended in a simple way w=
hile keeping the old interface intact.<br><br>### Inheritance ###<br><br>In=
heritance requires redefinition of all constructors, and creates a stricter=
<br>dependency between two classes than what is proposed here. Classes may =
be<br>converted to a common ancestor even though that is undesired or even =
dangerous<br>in case of implicit conversions.<br><br>Inheritance may also b=
e unwanted in order to avoid risks linked to polymorphism<br>and freeing da=
ta structures where the base class does not have a virtual<br>destructor.<b=
r><br>### Encapsulation with Manual Exposure of Needed Methods ###<br><br>T=
his method obviously requires a great deal of code to be rewritten in order=
to<br>wrap every single method that the old class was exposing.<br><br>In =
addition one needs to have intimate knowledge of the original interface in<=
br>order to be able to duplicate it correctly. Template methods, rvalue ref=
erences,<br>possibly undocumented methods which are required in order to al=
low the class to<br>behave in the same way as before. This heightens the ba=
r significantly for many<br>users, since they may not know correctly how to=
duplicate an interface and how<br>to forward parameters to the old interfa=
ce correctly.<br><br>The new code also must be maintained in case the old i=
nterface changes.<br><br>### Copying the Base Class ###<br><br>This can be =
useful, but requires all code to be duplicated, and thus<br>significantly i=
ncreases the burden of maintaining the code. All bugs discovered<br>in one =
class must be fixed in the other class too. All new features applied to<br>=
one class must be applied to the other too.<br><br>### Macro-expansion ###<=
br><br>Macro expansions can be used in order to encode the interface and im=
plementation<br>of a given class just one time, and used multiple times to =
produce separate<br>classes.<br><br>This approach is unfortunately not appl=
icable to existing code, and is very hard<br>to extend if one wants to copy=
a class but add additional functionality to it.<br><br>### Templates ###<b=
r><br>Templates produce for each instantiation a separate type. They are un=
fortunately<br>not applicable to previously existing code. For new code, th=
ey would require the<br>creation of "fake" template parameters th=
at would need to vary in order to<br>produce separate types.<br><br>In addi=
tion, class extension through templates is not possible: variations would<b=
r>need to be made through specialization, which itself requires copying exi=
sting<br>code.<br><br>Previous Work<br>-------------<br><br>Strong typedefs=
have already been proposed for the C++ language multiple times<br>([N1706]=
(<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.p=
df" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'http=
://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg=
21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQ=
jCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;" onclick=3D"this.href=3D&=
#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fs=
c22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sntz\x3d1\x26us=
g\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;">http://www.open-=
std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2004/n1706.pdf</a>),<br>[N1891=
](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.=
pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'htt=
p://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fw=
g21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAF=
QjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;" onclick=3D"this.href=3D=
'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2F=
sc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26sntz\x3d1\x26u=
sg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;">http://www.open=
-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2005/n1891.pdf</a>),<br>[N351=
5](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515=
..pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'ht=
tp://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2F=
wg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dA=
FQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;" onclick=3D"this.href=
=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1=
%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d1\x=
26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;">http://www.o=
pen-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2013/n3515.pdf</a>),<br>[N=
3741](<a href=3D"https://isocpp.org/files/papers/n3741.pdf)" target=3D"_bla=
nk" rel=3D"nofollow" onmousedown=3D"this.href=3D'https://www.google.com=
/url?q\x3dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pdf)\x26sa\x3dD=
\x26sntz\x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA';return true=
;" onclick=3D"this.href=3D'https://www.google.com/url?q\x3dhttps%3A%2F%=
2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pdf)\x26sa\x3dD\x26sntz\x3d1\x26usg\x=
3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA';return true;">https://isocpp.org/=
<wbr>files/papers/n3741.pdf)</a>). These typedefs are named<br>*opaque type=
defs*, and these papers try to explore and define exactly the<br>behavior t=
hat such typedefs should and would have when used to create new<br>types. I=
n particular, the keywords `public`, `protected` and `private` are used<br>=
in order to create a specific relation with the original type and how is th=
e<br>new type allowed to be cast back to the original type or be used in it=
s place<br>during overloads.<br><br>This document shares many of the the sa=
me principles, for example (quoting from<br>N3741):<br><br>> - Consisten=
t with restrictions imposed on analogous relationships such as<br>>=C2=
=A0=C2=A0 base classes underlying derived classes and integer types underly=
ing enums,<br>>=C2=A0=C2=A0 an underlying type should be (1) complete an=
d (2) not cv-quali=EF=AC=81ed. We also do<br>>=C2=A0=C2=A0 not require t=
hat any enum type, reference type, array type, function type, or<br>>=C2=
=A0=C2=A0 pointer-to-member type be allowed as an underlying type.<br><br>H=
owever, this document tries to propose a possibly more simple approach, whe=
re<br>a new language feature is introduced with the same meaning and functi=
onality as<br>if the user autonomously implemented a new class him/herself,=
matching the<br>original type completely. Thus, it should result for the u=
ser more simple to<br>understand (as it simply matches already the already =
understood mechanics of<br>creating a new, unique type from nothing), and n=
o new rules for type conversion<br>and selection on overloads have to be cr=
eated.<br><br>Syntax<br>------<br><br>### Simple Case ###<br><br>Syntax cou=
ld look something like this:<br><br>```cpp<br>class Base {<br>=C2=A0=C2=A0=
=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) =
{}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout <=
;< "foo " << x << "\n"; }<br>=C2=A0=C2=
=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>=
};<br><br>struct Copy : using Base {};<br><br>/* Equivalent to<br><br>struc=
t Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 vo=
id foo() { std::cout << "foo " << x << "\n=
"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br><br>One cannot copy a class a=
nd inherit at the same time. If such a class is needed<br>one would need to=
create it by hand with the desided functionality and<br>inheriting from th=
e desired classes, as it would be done normally.<br><br>All method implemen=
tations would be the same. The copied class would inherit<br>from the same =
classes its base class inherits from. All constructors would work<br>in the=
same way.<br><br>### Adding New Functionality ###<br><br>Ideally one could=
specify additional methods, separate from that of Base, to add<br>upon the=
existing functionality.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=
=A0 void foo() { std::cout << "foo\n"; }<br>};<br><br>struc=
t Derived : public Base {};<br><br>struct Copy : using Base {<br>=C2=A0=C2=
=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>};<br><br=
>struct CopyDerived : using Derived {};<br><br>/* Equivalent to<br><br>stru=
ct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n=
"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n=
"; }<br>};<br><br>struct CopyDerived : public Base {};<br><br>*/<br>``=
`<br><br>Only new methods need to be implemented for that class.<br><br>###=
# Interfacing with the Original Class ####<br><br>In order to interface wit=
h the original class, simple conversion operators can<br>be added by the us=
er explicitly at-will, in order to obtain the desired<br>interface. Note th=
at if more types with this kind of compatibility were needed,<br>one would =
only need to implement them once, since copying the produced type<br>would =
copy the new, more compatible interface with it.<br><br>```cpp<br>struct Ba=
se {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struct Copy : using Base {<br>=
=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>};<br>```<br><=
br>`reinterpret_cast` may also be used to convert back to the original clas=
s,<br>limited by the tool's already existing rules.<br><br>In general t=
he usual rules of `reinterpret_cast` apply to the copied classes<br>with re=
spect to their general classes, exactly as if the copied class had been<br>=
implemented by hand.<br><br>### Overloads ###<br><br>Duplicating an existin=
g class should allow for new overloads on the new type,<br>and no ambiguity=
between the copied class, the old class and other copied<br>classes.<br><b=
r>```cpp<br>class Position : using std::pair<double, double> {};<br>c=
lass Distance : using std::pair<double, double> {};<br><br>Position o=
perator+(const Position & p, const Distance & d) {<br>=C2=A0=C2=A0=
=C2=A0 return Position(p.first + d.first, p.second + d.second);<br>}<br><br=
>Distance operator+(const Distance & lhs, const Distance & rhs) {<b=
r>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rhs.first, lhs.second + rh=
s.second);<br>}<br><br>// ...<br><br>Position p(1, 1);<br>Distance d(1, 1);=
<br><br>p + d; // OK<br>d + d; // OK<br>p + p; // Error<br>```<br><br>### T=
emplated Class Copy ###<br><br>The user might want to create a single templ=
atized copy interface, and use it<br>multiple times. For example, one might=
want multiple copied classes which can<br>convert to their original. This =
could be done as follows:<br><br>```cpp<br>struct A { int x; };<br><br>temp=
late <typename T><br>struct TemplatizedCopy : using T {<br>=C2=A0=C2=
=A0=C2=A0 static_assert(std::is_<wbr>standard_layout<T>::value,<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this with a non-standard-la=
yout class");<br><br>=C2=A0=C2=A0=C2=A0 operator T&() { return *re=
interpret_cast<T*>(this); }<br>};<br><br>// Could be used either via =
normal typedefs<br>using Copy1 =3D TemplatizedCopy<A>;<br><br>// Or v=
ia copy, depending on requirements.<br>struct Copy2 : using TemplatizedCopy=
<A> {};<br>```<br><br>### Copying Template Classes ###<br><br>Since t=
he construct is similar to inheritance, the syntax for creating aliases<br>=
of templated classes could be the same:<br><br>```cpp<br>template <typen=
ame T><br>struct A {};<br><br>template <typename T><br>struct B : =
using A<T> {};<br><br>B<int> b;<br>```<br><br>The copied class =
must have the same number or less of template parameters than<br>the base c=
lass. Partial or full specializations of the base class can be allowed:<br>=
<br>```cpp<br>template <typename T, typename U><br>struct A {};<br><b=
r>template <typename T><br>struct B : using A<T, double> {};<br=
><br>B<int> b;<br>```<br><br>When the base class has partial speciali=
zations, only those who apply are copied<br>to the copied class.<br><br>```=
cpp<br>template <typename T, typename U><br>struct A { T t; U u; };<b=
r><br>template <typename U><br>struct A<double, U> { double y; =
U u; };<br><br>template <typename T><br>struct A<T, int> { T t;=
char z; };<br><br>template <typename T><br>struct B : using A<T, =
double> {};<br><br>/* Equivalent to<br><br>template <typename T><b=
r>struct B { T t; double u; };<br><br>template <><br>struct B<doub=
le> { double y; double u; };<br><br>*/<br>```<br><br>The copied class ca=
n add additional specializations. Or specializations for a<br>given class c=
an copy another.<br><br>```cpp<br>template <typename T><br>struct A {=
int x; };<br><br>struct B { char c; };<br><br>template <typename T><=
br>struct C : using A<T> {};<br><br>template <><br>struct C<=
double> : using B {};<br><br>template <><br>struct A<int> : =
using C<double> {};<br><br>/* Equivalent to<br><br>template<><b=
r>struct A<int> { char c; };<br><br>template <typename T><br>st=
ruct C { int x; };<br><br>template <><br>struct C<double> { cha=
r c; };<br><br>*/<br>```<br><br>### Copying Multiple Dependent Classes ###<=
br><br>Copying multiple classes using the simple syntax we have described c=
an be<br>impossible if those classes depend on one another. This is because=
each copy<br>would depend on the originals, rather than on the copied clas=
ses. A possible way<br>to specify such dependencies could be:<br><br>```cpp=
<br>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A * a;<br>};<br><br>s=
truct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>struct C;<br><br>struct D=
: using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A;<br>};<br><br>struct=
C : using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>};<br><br>/* E=
quivalent to<br><br>struct C;<br><br>struct D {<br>=C2=A0=C2=A0=C2=A0 C * a=
;<br>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<br>};<br><br>*/<br>```=
<br><br>`using class` has been used in order to disambiguate it from normal=
`using`<br>alias directive. `using class` is only valid when the left hand=
side has been<br>defined as a copy of the right hand side.<br><br>In case =
of a template base class using a template second class, one could<br>specif=
y different copies for certain specializations;<br><br>```cpp<br>template &=
lt;typename T><br>struct A {};<br><br>template <typename T><br>str=
uct B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><br>template <typen=
ame T><br>struct C : using A<T> {};<br><br>```<br><br>### Substitu=
ting Existing Functionality (Optional) ###<br><br>Ideally one may want to u=
se most of an implementation for another class, but<br>vary a certain numbe=
r of methods. In this case, if `Copy` contains a member<br>function that al=
ready exists in `Base`, then that implementation is substituted<br>in `Copy=
`. This may or may not be allowed for attributes.<br><br>```cpp<br>struct B=
ase {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n&quo=
t;; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&quo=
t;; }<br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 void fo=
o() { std::cout << "baz\n"; }<br>};<br><br>/* Equivalent to=
<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout <<=
"baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout <<=
"bar\n"; }<br>};<br><br>*/<br>```<br><br>A side effect of this i=
s that it could allow for some type of "interface", where<br>some=
base class could be defined as:<br><br>```cpp<br>struct Base {<br>=C2=A0=
=C2=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=A0=
=C2=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : using Base {<br>=C2=A0=
=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void baz();<br>=C2=
=A0=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/* Equivalent to<br><br=
>struct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=
=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<br>};<br><br>*/<br><br=
>struct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=
=A0=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalent to<br><br>struct Co=
py2 {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void foo();<b=
r>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br=
><br>*/<br>```<br><br>This feature could however present problems when the =
members changed also alter<br>behavior and/or variable types of non-modifie=
d member and non-member functions,<br>since the new behavior could be eithe=
r erroneous or ambiguous.<br><br>### Copying and Extending Primitive Types =
(Optional) ###<br><br>The same syntax could be used in order to extend prim=
itive types. Using the<br>extension that allows the modification of the cop=
ied types, this could allow for<br>creation of numeric types where some ope=
rations are disabled as needed.<br><br>```cpp<br>struct Id : using int {<br=
>=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 =
Id operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 // Non-explicitly de=
leted operators keep their validity<br><br>=C2=A0=C2=A0=C2=A0 // Defining n=
ew operators with the old type can allow interoperativity<br>=C2=A0=C2=A0=
=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0 // We can convert the c=
opied type to the old one.<br>=C2=A0=C2=A0=C2=A0 operator int() { return (*=
this) * 2; }<br>};<br><br>/* Equivalent to<br><br>class Id final {<br>=C2=
=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id op=
erator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id rhs) { return Id{lhs.v_=
- rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator=
+(Id, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { =
return v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<br><br>Note that when cop=
ying from a primitive types inheritance is forbidden as the<br>generated co=
py is `final` (although it is allowed to keep copying the newly<br>created =
class).<br><br>### STL Traits (Optional) ###<br><br>Traits could be include=
d in the standard library in order to determine whether a<br>class is a cop=
y of another, or if it has been derived from a copy<br>(copies/inheritances=
could be nested arbitrarily).<br><br>```cpp<br>struct Base {};<br><br>stru=
ct Copy : using Base {};<br><br>static_assert(std::is_copy<<wbr>Copy, Ba=
se>::value);<br><br>struct ChildCopy : public Copy {};<br><br>struct Cop=
yChildCopy : using ChildCopy {};<br><br>static_assert(std::is_copy_<wbr>bas=
e_of<Base, CopyChildCopy>::value);<br>```<br><br>Compatibility<br>---=
----------<br><br>As the syntax is new, no old code would be affected.<br><=
/span><br></div></blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/bd7f888f-d841-4f73-a148-dbb08f59faf0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/bd7f888f-d841-4f73-a148-dbb08f59faf0=
%40isocpp.org</a>.<br />
------=_Part_1736_1306221838.1482254298072--
------=_Part_1735_1433328500.1482254298071--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Tue, 20 Dec 2016 18:42:05 +0100
Raw View
--001a114e2b8006b16e05441a8e35
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
In your first example, B::Self would be B, as all old references to the
copied class are changed (as if by preprocessor in some sense) to the new
class.
In your second example, B's representation would be exactly the same as
this:
struct B {
using Self =3D B;
B& operator=3D(const Self&) { return *this; }
};
Aside from the fact that if needed one could find out, for example via
type_traits, that B is a copy of A. But for practical purpouses the class
would be that one.
On Tue, Dec 20, 2016 at 6:18 PM, S.B. <i.and.my.little.friends@gmail.com>
wrote:
> According to your proposal, what should B::Self be in the following
> example?
> struct A {
> using Self =3D A;
> };
> struct B : using A {};
>
>
> According to your proposal, how should the copy assignement operator of B
> look like?
> struct A {
> using Self =3D A;
> A& operator=3D(const Self&) { return *this; }
> };
>
> struct B : using A {};
>
>
>
>
> On Monday, December 19, 2016 at 7:04:48 PM UTC+8, sval...@gmail.com wrote=
:
>>
>> This is a stub proposal on strong typedefs, i.e. types that work in the
>> exact same way, but allow separate overloading. Other papers and proposa=
ls
>> exist, but I've tried a different approach that tries to mimic a more
>> inheritance-like syntax which might be more intuitive. The full text can=
be
>> found online at https://github.com/Svalorzen/CppCopyProposal.
>>
>> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text
>> below. Thanks in advance for your comments.
>>
>> Duplication and Extension of Existing Classes
>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>>
>> Introduction
>> ------------
>>
>> This document describes a possible approach to duplicate existing
>> functionality
>> while wrapping it in a new type, without the burden of inheritance and t=
o
>> allow
>> function overloads on syntactically identical but semantically different
>> types
>> (also known as *strong typedef*).
>>
>> The approach taken should be simple to implement and be applicable to
>> existing
>> code.
>>
>> Optional sections are to be read as additional ideas that could be furth=
er
>> developed or completely ignored. They are mostly food for thought, but
>> included
>> for completeness.
>>
>> Reasons
>> -------
>>
>> - Scientific libraries where a type has different behaviors depending on
>> context
>> have currently no simple way to indicate the semantic differences.
>> Since a
>> `typedef` does not allow multiple overloads on new typedef types -
>> since they
>> are still the "old" type - they have to resort to imperfect techniques=
,
>> such
>> as copying, wrapping or inheriting the needed type. Examples:
>> coordinates in a
>> plane (rectangular, polar), vectors of double (probabilities, values).
>> - Easier maintainability of code which is known to be the same, rather
>> than
>> being copy-pasted.
>> - Avoiding misuse of inheritance in order to provide a copy-paste
>> alternative.
>> This can result in very deep hierarchies of types which should really
>> not have
>> anything to do with each other.
>> - Enabling users to use an existing and presumably correct type but
>> partially
>> extend it with context-specific methods. Examples: search for
>> "`std::vector`
>> inheritance" yields many results of users trying to maintain the
>> original
>> interface and functionality but add one or two methods.
>>
>> The functionality should have the following requirements:
>>
>> - Can be applied to existing code.
>> - Should limit dependencies between new and old type as much as possible=
..
>> - Should allow for partial extensions of the old code.
>>
>> Alternatives
>> ------------
>>
>> ### Typedef / Using Directive ###
>>
>> Using a type alias creates an alternative name for a single type.
>> However, this
>> leaves no space to implement overloads that are context-specific. Nor a
>> type can
>> be extended in a simple way while keeping the old interface intact.
>>
>> ### Inheritance ###
>>
>> Inheritance requires redefinition of all constructors, and creates a
>> stricter
>> dependency between two classes than what is proposed here. Classes may b=
e
>> converted to a common ancestor even though that is undesired or even
>> dangerous
>> in case of implicit conversions.
>>
>> Inheritance may also be unwanted in order to avoid risks linked to
>> polymorphism
>> and freeing data structures where the base class does not have a virtual
>> destructor.
>>
>> ### Encapsulation with Manual Exposure of Needed Methods ###
>>
>> This method obviously requires a great deal of code to be rewritten in
>> order to
>> wrap every single method that the old class was exposing.
>>
>> In addition one needs to have intimate knowledge of the original
>> interface in
>> order to be able to duplicate it correctly. Template methods, rvalue
>> references,
>> possibly undocumented methods which are required in order to allow the
>> class to
>> behave in the same way as before. This heightens the bar significantly
>> for many
>> users, since they may not know correctly how to duplicate an interface
>> and how
>> to forward parameters to the old interface correctly.
>>
>> The new code also must be maintained in case the old interface changes.
>>
>> ### Copying the Base Class ###
>>
>> This can be useful, but requires all code to be duplicated, and thus
>> significantly increases the burden of maintaining the code. All bugs
>> discovered
>> in one class must be fixed in the other class too. All new features
>> applied to
>> one class must be applied to the other too.
>>
>> ### Macro-expansion ###
>>
>> Macro expansions can be used in order to encode the interface and
>> implementation
>> of a given class just one time, and used multiple times to produce
>> separate
>> classes.
>>
>> This approach is unfortunately not applicable to existing code, and is
>> very hard
>> to extend if one wants to copy a class but add additional functionality
>> to it.
>>
>> ### Templates ###
>>
>> Templates produce for each instantiation a separate type. They are
>> unfortunately
>> not applicable to previously existing code. For new code, they would
>> require the
>> creation of "fake" template parameters that would need to vary in order =
to
>> produce separate types.
>>
>> In addition, class extension through templates is not possible:
>> variations would
>> need to be made through specialization, which itself requires copying
>> existing
>> code.
>>
>> Previous Work
>> -------------
>>
>> Strong typedefs have already been proposed for the C++ language multiple
>> times
>> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/
>> 2004/n1706.pdf),
>> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pd=
f
>> ),
>> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pd=
f
>> ),
>> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are
>> named
>> *opaque typedefs*, and these papers try to explore and define exactly th=
e
>> behavior that such typedefs should and would have when used to create ne=
w
>> types. In particular, the keywords `public`, `protected` and `private`
>> are used
>> in order to create a specific relation with the original type and how is
>> the
>> new type allowed to be cast back to the original type or be used in its
>> place
>> during overloads.
>>
>> This document shares many of the the same principles, for example
>> (quoting from
>> N3741):
>>
>> > - Consistent with restrictions imposed on analogous relationships such
>> as
>> > base classes underlying derived classes and integer types underlying
>> enums,
>> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We
>> also do
>> > not require that any enum type, reference type, array type, function
>> type, or
>> > pointer-to-member type be allowed as an underlying type.
>>
>> However, this document tries to propose a possibly more simple approach,
>> where
>> a new language feature is introduced with the same meaning and
>> functionality as
>> if the user autonomously implemented a new class him/herself, matching t=
he
>> original type completely. Thus, it should result for the user more simpl=
e
>> to
>> understand (as it simply matches already the already understood mechanic=
s
>> of
>> creating a new, unique type from nothing), and no new rules for type
>> conversion
>> and selection on overloads have to be created.
>>
>> Syntax
>> ------
>>
>> ### Simple Case ###
>>
>> Syntax could look something like this:
>>
>> ```cpp
>> class Base {
>> public:
>> Base() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> struct Copy : using Base {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> public:
>> Copy() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> */
>> ```
>>
>> One cannot copy a class and inherit at the same time. If such a class is
>> needed
>> one would need to create it by hand with the desided functionality and
>> inheriting from the desired classes, as it would be done normally.
>>
>> All method implementations would be the same. The copied class would
>> inherit
>> from the same classes its base class inherits from. All constructors
>> would work
>> in the same way.
>>
>> ### Adding New Functionality ###
>>
>> Ideally one could specify additional methods, separate from that of Base=
,
>> to add
>> upon the existing functionality.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> };
>>
>> struct Derived : public Base {};
>>
>> struct Copy : using Base {
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : using Derived {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : public Base {};
>>
>> */
>> ```
>>
>> Only new methods need to be implemented for that class.
>>
>> #### Interfacing with the Original Class ####
>>
>> In order to interface with the original class, simple conversion
>> operators can
>> be added by the user explicitly at-will, in order to obtain the desired
>> interface. Note that if more types with this kind of compatibility were
>> needed,
>> one would only need to implement them once, since copying the produced
>> type
>> would copy the new, more compatible interface with it.
>>
>> ```cpp
>> struct Base {
>> public:
>> int x;
>>
>> private:
>> double y;
>> };
>>
>> struct Copy : using Base {
>> operator Base() { return Base{x, y}; }
>> };
>> ```
>>
>> `reinterpret_cast` may also be used to convert back to the original clas=
s,
>> limited by the tool's already existing rules.
>>
>> In general the usual rules of `reinterpret_cast` apply to the copied
>> classes
>> with respect to their general classes, exactly as if the copied class ha=
d
>> been
>> implemented by hand.
>>
>> ### Overloads ###
>>
>> Duplicating an existing class should allow for new overloads on the new
>> type,
>> and no ambiguity between the copied class, the old class and other copie=
d
>> classes.
>>
>> ```cpp
>> class Position : using std::pair<double, double> {};
>> class Distance : using std::pair<double, double> {};
>>
>> Position operator+(const Position & p, const Distance & d) {
>> return Position(p.first + d.first, p.second + d.second);
>> }
>>
>> Distance operator+(const Distance & lhs, const Distance & rhs) {
>> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
>> }
>>
>> // ...
>>
>> Position p(1, 1);
>> Distance d(1, 1);
>>
>> p + d; // OK
>> d + d; // OK
>> p + p; // Error
>> ```
>>
>> ### Templated Class Copy ###
>>
>> The user might want to create a single templatized copy interface, and
>> use it
>> multiple times. For example, one might want multiple copied classes whic=
h
>> can
>> convert to their original. This could be done as follows:
>>
>> ```cpp
>> struct A { int x; };
>>
>> template <typename T>
>> struct TemplatizedCopy : using T {
>> static_assert(std::is_standard_layout<T>::value,
>> "Can't use this with a non-standard-layout class");
>>
>> operator T&() { return *reinterpret_cast<T*>(this); }
>> };
>>
>> // Could be used either via normal typedefs
>> using Copy1 =3D TemplatizedCopy<A>;
>>
>> // Or via copy, depending on requirements.
>> struct Copy2 : using TemplatizedCopy<A> {};
>> ```
>>
>> ### Copying Template Classes ###
>>
>> Since the construct is similar to inheritance, the syntax for creating
>> aliases
>> of templated classes could be the same:
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T> {};
>>
>> B<int> b;
>> ```
>>
>> The copied class must have the same number or less of template parameter=
s
>> than
>> the base class. Partial or full specializations of the base class can be
>> allowed:
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> B<int> b;
>> ```
>>
>> When the base class has partial specializations, only those who apply ar=
e
>> copied
>> to the copied class.
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A { T t; U u; };
>>
>> template <typename U>
>> struct A<double, U> { double y; U u; };
>>
>> template <typename T>
>> struct A<T, int> { T t; char z; };
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> /* Equivalent to
>>
>> template <typename T>
>> struct B { T t; double u; };
>>
>> template <>
>> struct B<double> { double y; double u; };
>>
>> */
>> ```
>>
>> The copied class can add additional specializations. Or specializations
>> for a
>> given class can copy another.
>>
>> ```cpp
>> template <typename T>
>> struct A { int x; };
>>
>> struct B { char c; };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> template <>
>> struct C<double> : using B {};
>>
>> template <>
>> struct A<int> : using C<double> {};
>>
>> /* Equivalent to
>>
>> template<>
>> struct A<int> { char c; };
>>
>> template <typename T>
>> struct C { int x; };
>>
>> template <>
>> struct C<double> { char c; };
>>
>> */
>> ```
>>
>> ### Copying Multiple Dependent Classes ###
>>
>> Copying multiple classes using the simple syntax we have described can b=
e
>> impossible if those classes depend on one another. This is because each
>> copy
>> would depend on the originals, rather than on the copied classes. A
>> possible way
>> to specify such dependencies could be:
>>
>> ```cpp
>> struct A;
>>
>> struct B {
>> A * a;
>> };
>>
>> struct A {
>> B b;
>> };
>>
>> struct C;
>>
>> struct D : using B {
>> using class C =3D A;
>> };
>>
>> struct C : using A {
>> using class D =3D B;
>> };
>>
>> /* Equivalent to
>>
>> struct C;
>>
>> struct D {
>> C * a;
>> };
>>
>> struct C {
>> D b;
>> };
>>
>> */
>> ```
>>
>> `using class` has been used in order to disambiguate it from normal
>> `using`
>> alias directive. `using class` is only valid when the left hand side has
>> been
>> defined as a copy of the right hand side.
>>
>> In case of a template base class using a template second class, one coul=
d
>> specify different copies for certain specializations;
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B {
>> A<T> a;
>> };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> ```
>>
>> ### Substituting Existing Functionality (Optional) ###
>>
>> Ideally one may want to use most of an implementation for another class,
>> but
>> vary a certain number of methods. In this case, if `Copy` contains a
>> member
>> function that already exists in `Base`, then that implementation is
>> substituted
>> in `Copy`. This may or may not be allowed for attributes.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct Copy : using Base {
>> void foo() { std::cout << "baz\n"; }
>> };
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "baz\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> */
>> ```
>>
>> A side effect of this is that it could allow for some type of
>> "interface", where
>> some base class could be defined as:
>>
>> ```cpp
>> struct Base {
>> Base() =3D delete;
>> void foo();
>> void bar();
>> };
>>
>> struct Copy1 : using Base {
>> Copy1() =3D default;
>> void baz();
>> void foo() =3D delete;
>> };
>>
>> /* Equivalent to
>>
>> struct Copy1 {
>> Copy1() =3D default;
>> void bar();
>> void baz();
>> };
>>
>> */
>>
>> struct Copy2 : using Base {
>> Copy2(int);
>> void abc();
>> };
>>
>> /*
>>
>> Equivalent to
>>
>> struct Copy2 {
>> Copy2(int);
>> void foo();
>> void bar();
>> void abc();
>> };
>>
>> */
>> ```
>>
>> This feature could however present problems when the members changed als=
o
>> alter
>> behavior and/or variable types of non-modified member and non-member
>> functions,
>> since the new behavior could be either erroneous or ambiguous.
>>
>> ### Copying and Extending Primitive Types (Optional) ###
>>
>> The same syntax could be used in order to extend primitive types. Using
>> the
>> extension that allows the modification of the copied types, this could
>> allow for
>> creation of numeric types where some operations are disabled as needed.
>>
>> ```cpp
>> struct Id : using int {
>> Id operator+(Id, Id) =3D delete;
>> Id operator*(Id, Id) =3D delete;
>> // Non-explicitly deleted operators keep their validity
>>
>> // Defining new operators with the old type can allow interoperativi=
ty
>> Id operator+(Id, int);
>> // We can convert the copied type to the old one.
>> operator int() { return (*this) * 2; }
>> };
>>
>> /* Equivalent to
>>
>> class Id final {
>> public:
>> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
>> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>>
>> Id operator+(Id, int);
>> operator int() { return v_ * 2; }
>> private:
>> int v_;
>> };
>>
>> */
>> ```
>>
>> Note that when copying from a primitive types inheritance is forbidden a=
s
>> the
>> generated copy is `final` (although it is allowed to keep copying the
>> newly
>> created class).
>>
>> ### STL Traits (Optional) ###
>>
>> Traits could be included in the standard library in order to determine
>> whether a
>> class is a copy of another, or if it has been derived from a copy
>> (copies/inheritances could be nested arbitrarily).
>>
>> ```cpp
>> struct Base {};
>>
>> struct Copy : using Base {};
>>
>> static_assert(std::is_copy<Copy, Base>::value);
>>
>> struct ChildCopy : public Copy {};
>>
>> struct CopyChildCopy : using ChildCopy {};
>>
>> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
>> ```
>>
>> Compatibility
>> -------------
>>
>> As the syntax is new, no old code would be affected.
>>
>>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BsqEzTxkH7yDYUg4XBzeVzmBeh7FaB_Y2GZUF%=
2BZdVvBSQ%40mail.gmail.com.
--001a114e2b8006b16e05441a8e35
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div><div><div><div>In your first example, B::Self wo=
uld be B, as all old references to the copied class are changed (as if by p=
reprocessor in some sense) to the new class.<br><br></div>In your second ex=
ample, B's representation would be exactly the same as this:<br><br></d=
iv>struct B {<br></div>=C2=A0=C2=A0=C2=A0 using Self =3D B;<br></div>=C2=A0=
=C2=A0=C2=A0 B& operator=3D(const Self&) { return *this; }<br>};<br=
><br></div>Aside from the fact that if needed one could find out, for examp=
le via type_traits, that B is a copy of A. But for practical purpouses the =
class would be that one.<br></div><div class=3D"gmail_extra"><br><div class=
=3D"gmail_quote">On Tue, Dec 20, 2016 at 6:18 PM, S.B. <span dir=3D"ltr">&l=
t;<a href=3D"mailto:i.and.my.little.friends@gmail.com" target=3D"_blank">i.=
and.my.little.friends@gmail.com</a>></span> wrote:<br><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr">According to your proposal, what should <spa=
n style=3D"font-family:courier new,monospace">B::Self</span> be in the foll=
owing example?<br><div style=3D"background-color:rgb(250,250,250);border-co=
lor:rgb(187,187,187);border-style:solid;border-width:1px" class=3D"m_-65427=
08139265030900prettyprint"><code class=3D"m_-6542708139265030900prettyprint=
"><div class=3D"m_-6542708139265030900subprettyprint"><span style=3D"color:=
#008" class=3D"m_-6542708139265030900styled-by-prettify">struct</span><span=
style=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> A=
</span><span style=3D"color:#660" class=3D"m_-6542708139265030900styled-by=
-prettify">{</span><span style=3D"color:#000" class=3D"m_-65427081392650309=
00styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color:#008" c=
lass=3D"m_-6542708139265030900styled-by-prettify">using</span><span style=
=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> </span>=
<span style=3D"color:#606" class=3D"m_-6542708139265030900styled-by-prettif=
y">Self</span><span style=3D"color:#000" class=3D"m_-6542708139265030900sty=
led-by-prettify"> </span><span style=3D"color:#660" class=3D"m_-65427081392=
65030900styled-by-prettify">=3D</span><span style=3D"color:#000" class=3D"m=
_-6542708139265030900styled-by-prettify"> A</span><span style=3D"color:#660=
" class=3D"m_-6542708139265030900styled-by-prettify">;</span><span style=3D=
"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"><br></span>=
<span style=3D"color:#660" class=3D"m_-6542708139265030900styled-by-prettif=
y">};</span><span style=3D"color:#000" class=3D"m_-6542708139265030900style=
d-by-prettify"><br></span><span style=3D"color:#008" class=3D"m_-6542708139=
265030900styled-by-prettify">struct</span><span style=3D"color:#000" class=
=3D"m_-6542708139265030900styled-by-prettify"> B </span><span style=3D"colo=
r:#660" class=3D"m_-6542708139265030900styled-by-prettify">:</span><span st=
yle=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> </sp=
an><span style=3D"color:#008" class=3D"m_-6542708139265030900styled-by-pret=
tify">using</span><span style=3D"color:#000" class=3D"m_-654270813926503090=
0styled-by-prettify"> A </span><span style=3D"color:#660" class=3D"m_-65427=
08139265030900styled-by-prettify">{};</span><span style=3D"color:#000" clas=
s=3D"m_-6542708139265030900styled-by-prettify"><br></span></div></code></di=
v><br><br>According to your proposal, how should the copy assignement opera=
tor of B look like?<br><div style=3D"background-color:rgb(250,250,250);bord=
er-color:rgb(187,187,187);border-style:solid;border-width:1px" class=3D"m_-=
6542708139265030900prettyprint"><code class=3D"m_-6542708139265030900pretty=
print"><div class=3D"m_-6542708139265030900subprettyprint"><span style=3D"c=
olor:#008" class=3D"m_-6542708139265030900styled-by-prettify">struct</span>=
<span style=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettif=
y"> A </span><span style=3D"color:#660" class=3D"m_-6542708139265030900styl=
ed-by-prettify">{</span><span style=3D"color:#000" class=3D"m_-654270813926=
5030900styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color:#0=
08" class=3D"m_-6542708139265030900styled-by-prettify">using</span><span st=
yle=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> </sp=
an><span style=3D"color:#606" class=3D"m_-6542708139265030900styled-by-pret=
tify">Self</span><span style=3D"color:#000" class=3D"m_-6542708139265030900=
styled-by-prettify"> </span><span style=3D"color:#660" class=3D"m_-65427081=
39265030900styled-by-prettify">=3D</span><span style=3D"color:#000" class=
=3D"m_-6542708139265030900styled-by-prettify"> A</span><span style=3D"color=
:#660" class=3D"m_-6542708139265030900styled-by-prettify">;</span><span sty=
le=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"><br>=
=C2=A0 =C2=A0 A</span><span style=3D"color:#660" class=3D"m_-65427081392650=
30900styled-by-prettify">&</span><span style=3D"color:#000" class=3D"m_=
-6542708139265030900styled-by-prettify"> </span><span style=3D"color:#008" =
class=3D"m_-6542708139265030900styled-by-prettify">operator</span><span sty=
le=3D"color:#660" class=3D"m_-6542708139265030900styled-by-prettify">=3D(</=
span><span style=3D"color:#008" class=3D"m_-6542708139265030900styled-by-pr=
ettify">const</span><span style=3D"color:#000" class=3D"m_-6542708139265030=
900styled-by-prettify"> </span><span style=3D"color:#606" class=3D"m_-65427=
08139265030900styled-by-prettify">Self</span><span style=3D"color:#660" cla=
ss=3D"m_-6542708139265030900styled-by-prettify">&)</span><span style=3D=
"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> </span><sp=
an style=3D"color:#660" class=3D"m_-6542708139265030900styled-by-prettify">=
{</span><span style=3D"color:#000" class=3D"m_-6542708139265030900styled-by=
-prettify"> </span><span style=3D"color:#008" class=3D"m_-65427081392650309=
00styled-by-prettify">return</span><span style=3D"color:#000" class=3D"m_-6=
542708139265030900styled-by-prettify"> </span><span style=3D"color:#660" cl=
ass=3D"m_-6542708139265030900styled-by-prettify">*</span><span style=3D"col=
or:#008" class=3D"m_-6542708139265030900styled-by-prettify">this</span><spa=
n style=3D"color:#660" class=3D"m_-6542708139265030900styled-by-prettify">;=
</span><span style=3D"color:#000" class=3D"m_-6542708139265030900styled-by-=
prettify"> </span><span style=3D"color:#660" class=3D"m_-654270813926503090=
0styled-by-prettify">}</span><span style=3D"color:#000" class=3D"m_-6542708=
139265030900styled-by-prettify"><br></span><span style=3D"color:#660" class=
=3D"m_-6542708139265030900styled-by-prettify">};</span><span style=3D"color=
:#000" class=3D"m_-6542708139265030900styled-by-prettify"><br><br></span><s=
pan style=3D"color:#008" class=3D"m_-6542708139265030900styled-by-prettify"=
>struct</span><span style=3D"color:#000" class=3D"m_-6542708139265030900sty=
led-by-prettify"> B </span><span style=3D"color:#660" class=3D"m_-654270813=
9265030900styled-by-prettify">:</span><span style=3D"color:#000" class=3D"m=
_-6542708139265030900styled-by-prettify"> </span><span style=3D"color:#008"=
class=3D"m_-6542708139265030900styled-by-prettify">using</span><span style=
=3D"color:#000" class=3D"m_-6542708139265030900styled-by-prettify"> A </spa=
n><span style=3D"color:#660" class=3D"m_-6542708139265030900styled-by-prett=
ify">{};</span><span style=3D"color:#000" class=3D"m_-6542708139265030900st=
yled-by-prettify"><br></span></div></code></div><div><div class=3D"h5"><br>=
<br><br><br>On Monday, December 19, 2016 at 7:04:48 PM UTC+8, <a href=3D"ma=
ilto:sval...@gmail.com" target=3D"_blank">sval...@gmail.com</a> wrote:<bloc=
kquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-lef=
t:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">This is a stub proposal=
on strong typedefs, i.e. types that work in the exact same way, but allow =
separate overloading. Other papers and proposals exist, but I've tried =
a different approach that tries to mimic a more inheritance-like syntax whi=
ch might be more intuitive. The full text can be found online at <a href=3D=
"https://github.com/Svalorzen/CppCopyProposal" rel=3D"nofollow" target=3D"_=
blank">https://github.com/Svalorzen/C<wbr>ppCopyProposal.<br><br></a>I'=
m copying the text below. Thanks in advance for your comments.<br><br><span=
style=3D"font-family:courier new,monospace">Duplication and Extension of E=
xisting Classes<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D<br><br>Introduction<br>------------<br><br>This document descr=
ibes a possible approach to duplicate existing functionality<br>while wrapp=
ing it in a new type, without the burden of inheritance and to allow<br>fun=
ction overloads on syntactically identical but semantically different types=
<br>(also known as *strong typedef*).<br><br>The approach taken should be s=
imple to implement and be applicable to existing<br>code.<br><br>Optional s=
ections are to be read as additional ideas that could be further<br>develop=
ed or completely ignored. They are mostly food for thought, but included<br=
>for completeness.<br><br>Reasons<br>-------<br><br>- Scientific libraries =
where a type has different behaviors depending on context<br>=C2=A0 have cu=
rrently no simple way to indicate the semantic differences. Since a<br>=C2=
=A0 `typedef` does not allow multiple overloads on new typedef types - sinc=
e they<br>=C2=A0 are still the "old" type - they have to resort t=
o imperfect techniques, such<br>=C2=A0 as copying, wrapping or inheriting t=
he needed type. Examples: coordinates in a<br>=C2=A0 plane (rectangular, po=
lar), vectors of double (probabilities, values).<br>- Easier maintainabilit=
y of code which is known to be the same, rather than<br>=C2=A0 being copy-p=
asted.<br>- Avoiding misuse of inheritance in order to provide a copy-paste=
alternative.<br>=C2=A0 This can result in very deep hierarchies of types w=
hich should really not have<br>=C2=A0 anything to do with each other.<br>- =
Enabling users to use an existing and presumably correct type but partially=
<br>=C2=A0 extend it with context-specific methods. Examples: search for &q=
uot;`std::vector`<br>=C2=A0 inheritance" yields many results of users =
trying to maintain the original<br>=C2=A0 interface and functionality but a=
dd one or two methods.<br><br>The functionality should have the following r=
equirements:<br><br>- Can be applied to existing code.<br>- Should limit de=
pendencies between new and old type as much as possible.<br>- Should allow =
for partial extensions of the old code.<br><br>Alternatives<br>------------=
<br><br>### Typedef / Using Directive ###<br><br>Using a type alias creates=
an alternative name for a single type. However, this<br>leaves no space to=
implement overloads that are context-specific. Nor a type can<br>be extend=
ed in a simple way while keeping the old interface intact.<br><br>### Inher=
itance ###<br><br>Inheritance requires redefinition of all constructors, an=
d creates a stricter<br>dependency between two classes than what is propose=
d here. Classes may be<br>converted to a common ancestor even though that i=
s undesired or even dangerous<br>in case of implicit conversions.<br><br>In=
heritance may also be unwanted in order to avoid risks linked to polymorphi=
sm<br>and freeing data structures where the base class does not have a virt=
ual<br>destructor.<br><br>### Encapsulation with Manual Exposure of Needed =
Methods ###<br><br>This method obviously requires a great deal of code to b=
e rewritten in order to<br>wrap every single method that the old class was =
exposing.<br><br>In addition one needs to have intimate knowledge of the or=
iginal interface in<br>order to be able to duplicate it correctly. Template=
methods, rvalue references,<br>possibly undocumented methods which are req=
uired in order to allow the class to<br>behave in the same way as before. T=
his heightens the bar significantly for many<br>users, since they may not k=
now correctly how to duplicate an interface and how<br>to forward parameter=
s to the old interface correctly.<br><br>The new code also must be maintain=
ed in case the old interface changes.<br><br>### Copying the Base Class ###=
<br><br>This can be useful, but requires all code to be duplicated, and thu=
s<br>significantly increases the burden of maintaining the code. All bugs d=
iscovered<br>in one class must be fixed in the other class too. All new fea=
tures applied to<br>one class must be applied to the other too.<br><br>### =
Macro-expansion ###<br><br>Macro expansions can be used in order to encode =
the interface and implementation<br>of a given class just one time, and use=
d multiple times to produce separate<br>classes.<br><br>This approach is un=
fortunately not applicable to existing code, and is very hard<br>to extend =
if one wants to copy a class but add additional functionality to it.<br><br=
>### Templates ###<br><br>Templates produce for each instantiation a separa=
te type. They are unfortunately<br>not applicable to previously existing co=
de. For new code, they would require the<br>creation of "fake" te=
mplate parameters that would need to vary in order to<br>produce separate t=
ypes.<br><br>In addition, class extension through templates is not possible=
: variations would<br>need to be made through specialization, which itself =
requires copying existing<br>code.<br><br>Previous Work<br>-------------<br=
><br>Strong typedefs have already been proposed for the C++ language multip=
le times<br>([N1706](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs=
/papers/2004/n1706.pdf" rel=3D"nofollow" target=3D"_blank">http://www.open-=
std.o<wbr>rg/jtc1/sc22/wg21/docs/papers/<wbr>2004/n1706.pdf</a>),<br>[N1891=
](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.=
pdf" rel=3D"nofollow" target=3D"_blank">http://www.open-std.or<wbr>g/jtc1/s=
c22/wg21/docs/papers/<wbr>2005/n1891.pdf</a>),<br>[N3515](<a href=3D"http:/=
/www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf" rel=3D"nofollo=
w" target=3D"_blank">http://www.open-std.or<wbr>g/jtc1/sc22/wg21/docs/paper=
s/<wbr>2013/n3515.pdf</a>),<br>[N3741](<a href=3D"https://isocpp.org/files/=
papers/n3741.pdf)" rel=3D"nofollow" target=3D"_blank">https://isocpp.org/fi=
l<wbr>es/papers/n3741.pdf)</a>). These typedefs are named<br>*opaque typede=
fs*, and these papers try to explore and define exactly the<br>behavior tha=
t such typedefs should and would have when used to create new<br>types. In =
particular, the keywords `public`, `protected` and `private` are used<br>in=
order to create a specific relation with the original type and how is the<=
br>new type allowed to be cast back to the original type or be used in its =
place<br>during overloads.<br><br>This document shares many of the the same=
principles, for example (quoting from<br>N3741):<br><br>> - Consistent =
with restrictions imposed on analogous relationships such as<br>>=C2=A0=
=C2=A0 base classes underlying derived classes and integer types underlying=
enums,<br>>=C2=A0=C2=A0 an underlying type should be (1) complete and (=
2) not cv-quali=EF=AC=81ed. We also do<br>>=C2=A0=C2=A0 not require that=
any enum type, reference type, array type, function type, or<br>>=C2=A0=
=C2=A0 pointer-to-member type be allowed as an underlying type.<br><br>Howe=
ver, this document tries to propose a possibly more simple approach, where<=
br>a new language feature is introduced with the same meaning and functiona=
lity as<br>if the user autonomously implemented a new class him/herself, ma=
tching the<br>original type completely. Thus, it should result for the user=
more simple to<br>understand (as it simply matches already the already und=
erstood mechanics of<br>creating a new, unique type from nothing), and no n=
ew rules for type conversion<br>and selection on overloads have to be creat=
ed.<br><br>Syntax<br>------<br><br>### Simple Case ###<br><br>Syntax could =
look something like this:<br><br>```cpp<br>class Base {<br>=C2=A0=C2=A0=C2=
=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) {}<=
br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout <&l=
t; "foo " << x << "\n"; }<br>=C2=A0=C2=A0=
=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<=
br><br>struct Copy : using Base {};<br><br>/* Equivalent to<br><br>struct C=
opy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void =
foo() { std::cout << "foo " << x << "\n&qu=
ot;; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br><br>One cannot copy a class and =
inherit at the same time. If such a class is needed<br>one would need to cr=
eate it by hand with the desided functionality and<br>inheriting from the d=
esired classes, as it would be done normally.<br><br>All method implementat=
ions would be the same. The copied class would inherit<br>from the same cla=
sses its base class inherits from. All constructors would work<br>in the sa=
me way.<br><br>### Adding New Functionality ###<br><br>Ideally one could sp=
ecify additional methods, separate from that of Base, to add<br>upon the ex=
isting functionality.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 =
void foo() { std::cout << "foo\n"; }<br>};<br><br>struct De=
rived : public Base {};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=
=C2=A0 void bar() { std::cout << "bar\n"; }<br>};<br><br>st=
ruct CopyDerived : using Derived {};<br><br>/* Equivalent to<br><br>struct =
Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n&qu=
ot;; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&qu=
ot;; }<br>};<br><br>struct CopyDerived : public Base {};<br><br>*/<br>```<b=
r><br>Only new methods need to be implemented for that class.<br><br>#### I=
nterfacing with the Original Class ####<br><br>In order to interface with t=
he original class, simple conversion operators can<br>be added by the user =
explicitly at-will, in order to obtain the desired<br>interface. Note that =
if more types with this kind of compatibility were needed,<br>one would onl=
y need to implement them once, since copying the produced type<br>would cop=
y the new, more compatible interface with it.<br><br>```cpp<br>struct Base =
{<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struct Copy : using Base {<br>=C2=
=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>};<br>```<br><br>=
`reinterpret_cast` may also be used to convert back to the original class,<=
br>limited by the tool's already existing rules.<br><br>In general the =
usual rules of `reinterpret_cast` apply to the copied classes<br>with respe=
ct to their general classes, exactly as if the copied class had been<br>imp=
lemented by hand.<br><br>### Overloads ###<br><br>Duplicating an existing c=
lass should allow for new overloads on the new type,<br>and no ambiguity be=
tween the copied class, the old class and other copied<br>classes.<br><br>`=
``cpp<br>class Position : using std::pair<double, double> {};<br>clas=
s Distance : using std::pair<double, double> {};<br><br>Position oper=
ator+(const Position & p, const Distance & d) {<br>=C2=A0=C2=A0=C2=
=A0 return Position(p.first + d.first, p.second + d.second);<br>}<br><br>Di=
stance operator+(const Distance & lhs, const Distance & rhs) {<br>=
=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rhs.first, lhs.second + rhs.=
second);<br>}<br><br>// ...<br><br>Position p(1, 1);<br>Distance d(1, 1);<b=
r><br>p + d; // OK<br>d + d; // OK<br>p + p; // Error<br>```<br><br>### Tem=
plated Class Copy ###<br><br>The user might want to create a single templat=
ized copy interface, and use it<br>multiple times. For example, one might w=
ant multiple copied classes which can<br>convert to their original. This co=
uld be done as follows:<br><br>```cpp<br>struct A { int x; };<br><br>templa=
te <typename T><br>struct TemplatizedCopy : using T {<br>=C2=A0=C2=A0=
=C2=A0 static_assert(std::is_standard<wbr>_layout<T>::value,<br>=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this with a non-standard-layou=
t class");<br><br>=C2=A0=C2=A0=C2=A0 operator T&() { return *reint=
erpret_cast<T*>(this); }<br>};<br><br>// Could be used either via nor=
mal typedefs<br>using Copy1 =3D TemplatizedCopy<A>;<br><br>// Or via =
copy, depending on requirements.<br>struct Copy2 : using TemplatizedCopy<=
;A> {};<br>```<br><br>### Copying Template Classes ###<br><br>Since the =
construct is similar to inheritance, the syntax for creating aliases<br>of =
templated classes could be the same:<br><br>```cpp<br>template <typename=
T><br>struct A {};<br><br>template <typename T><br>struct B : usi=
ng A<T> {};<br><br>B<int> b;<br>```<br><br>The copied class mus=
t have the same number or less of template parameters than<br>the base clas=
s. Partial or full specializations of the base class can be allowed:<br><br=
>```cpp<br>template <typename T, typename U><br>struct A {};<br><br>t=
emplate <typename T><br>struct B : using A<T, double> {};<br><b=
r>B<int> b;<br>```<br><br>When the base class has partial specializat=
ions, only those who apply are copied<br>to the copied class.<br><br>```cpp=
<br>template <typename T, typename U><br>struct A { T t; U u; };<br><=
br>template <typename U><br>struct A<double, U> { double y; U u=
; };<br><br>template <typename T><br>struct A<T, int> { T t; ch=
ar z; };<br><br>template <typename T><br>struct B : using A<T, dou=
ble> {};<br><br>/* Equivalent to<br><br>template <typename T><br>s=
truct B { T t; double u; };<br><br>template <><br>struct B<double&=
gt; { double y; double u; };<br><br>*/<br>```<br><br>The copied class can a=
dd additional specializations. Or specializations for a<br>given class can =
copy another.<br><br>```cpp<br>template <typename T><br>struct A { in=
t x; };<br><br>struct B { char c; };<br><br>template <typename T><br>=
struct C : using A<T> {};<br><br>template <><br>struct C<dou=
ble> : using B {};<br><br>template <><br>struct A<int> : usi=
ng C<double> {};<br><br>/* Equivalent to<br><br>template<><br>s=
truct A<int> { char c; };<br><br>template <typename T><br>struc=
t C { int x; };<br><br>template <><br>struct C<double> { char c=
; };<br><br>*/<br>```<br><br>### Copying Multiple Dependent Classes ###<br>=
<br>Copying multiple classes using the simple syntax we have described can =
be<br>impossible if those classes depend on one another. This is because ea=
ch copy<br>would depend on the originals, rather than on the copied classes=
.. A possible way<br>to specify such dependencies could be:<br><br>```cpp<br=
>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A * a;<br>};<br><br>stru=
ct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>struct C;<br><br>struct D : =
using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A;<br>};<br><br>struct C =
: using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>};<br><br>/* Equi=
valent to<br><br>struct C;<br><br>struct D {<br>=C2=A0=C2=A0=C2=A0 C * a;<b=
r>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<br>};<br><br>*/<br>```<br=
><br>`using class` has been used in order to disambiguate it from normal `u=
sing`<br>alias directive. `using class` is only valid when the left hand si=
de has been<br>defined as a copy of the right hand side.<br><br>In case of =
a template base class using a template second class, one could<br>specify d=
ifferent copies for certain specializations;<br><br>```cpp<br>template <=
typename T><br>struct A {};<br><br>template <typename T><br>struct=
B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><br>template <typename=
T><br>struct C : using A<T> {};<br><br>```<br><br>### Substitutin=
g Existing Functionality (Optional) ###<br><br>Ideally one may want to use =
most of an implementation for another class, but<br>vary a certain number o=
f methods. In this case, if `Copy` contains a member<br>function that alrea=
dy exists in `Base`, then that implementation is substituted<br>in `Copy`. =
This may or may not be allowed for attributes.<br><br>```cpp<br>struct Base=
{<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n";=
}<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n";=
}<br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 void foo()=
{ std::cout << "baz\n"; }<br>};<br><br>/* Equivalent to<br=
><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << &q=
uot;baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << &q=
uot;bar\n"; }<br>};<br><br>*/<br>```<br><br>A side effect of this is t=
hat it could allow for some type of "interface", where<br>some ba=
se class could be defined as:<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=
=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=A0=C2=
=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : using Base {<br>=C2=A0=C2=
=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void baz();<br>=C2=A0=
=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/* Equivalent to<br><br>st=
ruct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=
=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<br>};<br><br>*/<br><br>st=
ruct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=
=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalent to<br><br>struct Copy2=
{<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=
=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><=
br>*/<br>```<br><br>This feature could however present problems when the me=
mbers changed also alter<br>behavior and/or variable types of non-modified =
member and non-member functions,<br>since the new behavior could be either =
erroneous or ambiguous.<br><br>### Copying and Extending Primitive Types (O=
ptional) ###<br><br>The same syntax could be used in order to extend primit=
ive types. Using the<br>extension that allows the modification of the copie=
d types, this could allow for<br>creation of numeric types where some opera=
tions are disabled as needed.<br><br>```cpp<br>struct Id : using int {<br>=
=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 I=
d operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 // Non-explicitly del=
eted operators keep their validity<br><br>=C2=A0=C2=A0=C2=A0 // Defining ne=
w operators with the old type can allow interoperativity<br>=C2=A0=C2=A0=C2=
=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0 // We can convert the copi=
ed type to the old one.<br>=C2=A0=C2=A0=C2=A0 operator int() { return (*thi=
s) * 2; }<br>};<br><br>/* Equivalent to<br><br>class Id final {<br>=C2=A0=
=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id opera=
tor/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - =
rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator+(I=
d, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { ret=
urn v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<br><br>Note that when copyin=
g from a primitive types inheritance is forbidden as the<br>generated copy =
is `final` (although it is allowed to keep copying the newly<br>created cla=
ss).<br><br>### STL Traits (Optional) ###<br><br>Traits could be included i=
n the standard library in order to determine whether a<br>class is a copy o=
f another, or if it has been derived from a copy<br>(copies/inheritances co=
uld be nested arbitrarily).<br><br>```cpp<br>struct Base {};<br><br>struct =
Copy : using Base {};<br><br>static_assert(std::is_copy<Cop<wbr>y, Base&=
gt;::value);<br><br>struct ChildCopy : public Copy {};<br><br>struct CopyCh=
ildCopy : using ChildCopy {};<br><br>static_assert(std::is_copy_bas<wbr>e_o=
f<Base, CopyChildCopy>::value);<br>```<br><br>Compatibility<br>------=
-------<br><br>As the syntax is new, no old code would be affected.<br></sp=
an><br></div></blockquote></div></div></div></blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BsqEzTxkH7yDYUg4XBzeVzmBeh7=
FaB_Y2GZUF%2BZdVvBSQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
sqEzTxkH7yDYUg4XBzeVzmBeh7FaB_Y2GZUF%2BZdVvBSQ%40mail.gmail.com</a>.<br />
--001a114e2b8006b16e05441a8e35--
.
Author: "D. B." <db0451@gmail.com>
Date: Tue, 20 Dec 2016 17:49:59 +0000
Raw View
--001a114426123c5c0405441aaa72
Content-Type: text/plain; charset=UTF-8
A quick comment on one thing that stuck out to me while skimming. For now
I'll leave the real review to those with more time/experience.
Is reinterpret_cast really the correct tool for this? It seems to me
like static_cast
would be more appropriate.
Think int vs enum class. The types are not implicitly substitutable but are
*really* the same, or at least sub/supersets... sound familiar? So an
explicit static_cast should be safe and preferable, by my understanding.
To me reinterpret_cast signals (screams) 'I probably shouldn't be doing
this, but there's no other way, and I promise this pointer/reference was
originally (compatible with) what I'm saying it is... honest'.
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com.
--001a114426123c5c0405441aaa72
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>A quick comment on one thing that stuck out to me whi=
le skimming. For now I'll leave the real review to those with more time=
/experience.<br><br></div>Is <font face=3D"monospace,monospace">reinterpret=
_cast<font face=3D"arial,helvetica,sans-serif"> really the correct tool for=
this? It seems to me like <font face=3D"monospace,monospace">static_cast <=
font face=3D"arial,helvetica,sans-serif">would be more appropriate.<br><br>=
Think <span style=3D"font-family:monospace,monospace">int </span>vs <span s=
tyle=3D"font-family:monospace,monospace">enum class</span>. The types are n=
ot implicitly substitutable but are <i>really</i> the same, or at least sub=
/supersets... sound familiar? So an explicit static_cast should be safe and=
preferable, by my understanding.<br><br>To me <font face=3D"monospace,mono=
space">reinterpret_cast<font face=3D"arial,helvetica,sans-serif"> signals (=
screams) 'I probably shouldn't be doing this, but there's no ot=
her way, and I promise this pointer/reference was originally (compatible wi=
th) what I'm saying it is... honest'.</font></font></font></font></=
font></font><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU=
5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0=
orere%3DYZ2_y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com</a>.<br />
--001a114426123c5c0405441aaa72--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Tue, 20 Dec 2016 19:02:06 +0100
Raw View
--001a113d1ea893ec0a05441ad574
Content-Type: text/plain; charset=UTF-8
I'm not sure you can `static_cast` between pointers of unrelated classes (I
think not actually). `reinterpret_cast` is also very limited in what it can
do in this case: I'm not 100% sure on the details, but in general I think
it is allowed only when the two classes are `standard_layout` (which has a
bunch of restrictions).
In any case, please note that `reinterpret_cast` is used as an example, and
it would still keep all already existing rules with no modifications, as
this proposal does not even try to go there. How an user would like to use
the feature and define additional methods is his/her concern. In terms of
the proposal, all cpp features work as if the user had implemented the new
class by hand, so no new rules have to be introduced.
On Tue, Dec 20, 2016 at 6:49 PM, D. B. <db0451@gmail.com> wrote:
> A quick comment on one thing that stuck out to me while skimming. For now
> I'll leave the real review to those with more time/experience.
>
> Is reinterpret_cast really the correct tool for this? It seems to me like static_cast
> would be more appropriate.
>
> Think int vs enum class. The types are not implicitly substitutable but
> are *really* the same, or at least sub/supersets... sound familiar? So an
> explicit static_cast should be safe and preferable, by my understanding.
>
> To me reinterpret_cast signals (screams) 'I probably shouldn't be doing
> this, but there's no other way, and I promise this pointer/reference was
> originally (compatible with) what I'm saying it is... honest'.
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_
> y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW32x0pGggvMP%3DFOY8xQ%40mail.gmail.com.
--001a113d1ea893ec0a05441ad574
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>I'm not sure you can `static_cast` between pointe=
rs of unrelated classes (I think not actually). `reinterpret_cast` is also =
very limited in what it can do in this case: I'm not 100% sure on the d=
etails, but in general I think it is allowed only when the two classes are =
`standard_layout` (which has a bunch of restrictions).<br><br></div>In any =
case, please note that `reinterpret_cast` is used as an example, and it wou=
ld still keep all already existing rules with no modifications, as this pro=
posal does not even try to go there. How an user would like to use the feat=
ure and define additional methods is his/her concern. In terms of the propo=
sal, all cpp features work as if the user had implemented the new class by =
hand, so no new rules have to be introduced.<br></div><div class=3D"gmail_e=
xtra"><br><div class=3D"gmail_quote">On Tue, Dec 20, 2016 at 6:49 PM, D. B.=
<span dir=3D"ltr"><<a href=3D"mailto:db0451@gmail.com" target=3D"_blank=
">db0451@gmail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quot=
e" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">=
<div dir=3D"ltr"><div>A quick comment on one thing that stuck out to me whi=
le skimming. For now I'll leave the real review to those with more time=
/experience.<br><br></div>Is <font face=3D"monospace,monospace">reinterpret=
_cast<font face=3D"arial,helvetica,sans-serif"> really the correct tool for=
this? It seems to me like <font face=3D"monospace,monospace">static_cast <=
font face=3D"arial,helvetica,sans-serif">would be more appropriate.<br><br>=
Think <span style=3D"font-family:monospace,monospace">int </span>vs <span s=
tyle=3D"font-family:monospace,monospace">enum class</span>. The types are n=
ot implicitly substitutable but are <i>really</i> the same, or at least sub=
/supersets... sound familiar? So an explicit static_cast should be safe and=
preferable, by my understanding.<br><br>To me <font face=3D"monospace,mono=
space">reinterpret_cast<font face=3D"arial,helvetica,sans-serif"> signals (=
screams) 'I probably shouldn't be doing this, but there's no ot=
her way, and I promise this pointer/reference was originally (compatible wi=
th) what I'm saying it is... honest'.</font></font></font></font></=
font></font><br></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU=
5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/st=
d-<wbr>proposals/<wbr>CACGiwhHGNADMd0orere%3DYZ2_<wbr>y7UB8Y0MPU5p25d1fE8i2=
WKrpA%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW=
32x0pGggvMP%3DFOY8xQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
sw7zmU8iz7Ysc3e7cpvf3GdrZW32x0pGggvMP%3DFOY8xQ%40mail.gmail.com</a>.<br />
--001a113d1ea893ec0a05441ad574--
.
Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Tue, 20 Dec 2016 15:58:30 -0800 (PST)
Raw View
------=_Part_104_208211713.1482278310447
Content-Type: multipart/alternative;
boundary="----=_Part_105_172844348.1482278310449"
------=_Part_105_172844348.1482278310449
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
I like the basic idea but I think it may get too complicated if=20
replacements and extensions are allowed. Isn't this what we have=20
inheritance for?
For the part about interdependent classes which need to get copied I think=
=20
your example violates your rule as these two classes are dependant in both=
=20
directions, the rule needs to be more lenient when it comes to ordering of=
=20
declarations.
I think that the most common case of interdependant groups of classes to=20
get copies will be parent and child classes. Would your idea with a nested=
=20
"using class C =3D A" cover that case to? I think an example of how this=20
would look would be warranted.
I think that making strong typedefs of primitive types is maybe the most=20
important case. It does seem very odd to use the keyword 'struct' to=20
achieve this... then again, without thinking too deeply about it I could=20
find no compelling reason that you would not be able to inherit from=20
primitive types. This would make the struct keyword more appropriate as you=
=20
can inherit a struct from a primitive type and redefine its functions=20
(which of those are to be considered as free or member functions is another=
=20
issue).
Finally, if you add copy ctors and cast operators to/from the original=20
types, doesn't this defy the purpose of the "strong" in the typedef? Or do=
=20
you mean that such cast operators are implicitly explicit? My take on this=
=20
would be that there should probably be explicit conversion possibilities=20
between original and copy unless maybe if you =3D delete them.
Den m=C3=A5ndag 19 december 2016 kl. 12:04:48 UTC+1 skrev sval...@gmail.com=
:
>
> This is a stub proposal on strong typedefs, i.e. types that work in the=
=20
> exact same way, but allow separate overloading. Other papers and proposal=
s=20
> exist, but I've tried a different approach that tries to mimic a more=20
> inheritance-like syntax which might be more intuitive. The full text can =
be=20
> found online at https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.=
=20
> Thanks in advance for your comments.
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing=20
> functionality
> while wrapping it in a new type, without the burden of inheritance and to=
=20
> allow
> function overloads on syntactically identical but semantically different=
=20
> types
> (also known as *strong typedef*).
>
> The approach taken should be simple to implement and be applicable to=20
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but=20
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending on=
=20
> context
> have currently no simple way to indicate the semantic differences. Sinc=
e=20
> a
> `typedef` does not allow multiple overloads on new typedef types - sinc=
e=20
> they
> are still the "old" type - they have to resort to imperfect techniques,=
=20
> such
> as copying, wrapping or inheriting the needed type. Examples:=20
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather th=
an
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste=20
> alternative.
> This can result in very deep hierarchies of types which should really=
=20
> not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but=20
> partially
> extend it with context-specific methods. Examples: search for=20
> "`std::vector`
> inheritance" yields many results of users trying to maintain the origin=
al
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type. However=
,=20
> this
> leaves no space to implement overloads that are context-specific. Nor a=
=20
> type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a=20
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even=20
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to=20
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in=20
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original interfac=
e=20
> in
> order to be able to duplicate it correctly. Template methods, rvalue=20
> references,
> possibly undocumented methods which are required in order to allow the=20
> class to
> behave in the same way as before. This heightens the bar significantly fo=
r=20
> many
> users, since they may not know correctly how to duplicate an interface an=
d=20
> how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs=20
> discovered
> in one class must be fixed in the other class too. All new features=20
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and=20
> implementation
> of a given class just one time, and used multiple times to produce separa=
te
> classes.
>
> This approach is unfortunately not applicable to existing code, and is=20
> very hard
> to extend if one wants to copy a class but add additional functionality t=
o=20
> it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are=20
> unfortunately
> not applicable to previously existing code. For new code, they would=20
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible: variation=
s=20
> would
> need to be made through specialization, which itself requires copying=20
> existing
> code.
>
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language multiple=
=20
> times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f
> ),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf
> ),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
> ),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are=
=20
> named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private` ar=
e=20
> used
> in order to create a specific relation with the original type and how is=
=20
> the
> new type allowed to be cast back to the original type or be used in its=
=20
> place
> during overloads.
>
> This document shares many of the the same principles, for example (quotin=
g=20
> from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships such =
as
> > base classes underlying derived classes and integer types underlying=
=20
> enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We=20
> also do
> > not require that any enum type, reference type, array type, function=
=20
> type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple approach,=
=20
> where
> a new language feature is introduced with the same meaning and=20
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more simple=
=20
> to
> understand (as it simply matches already the already understood mechanics=
=20
> of
> creating a new, unique type from nothing), and no new rules for type=20
> conversion
> and selection on overloads have to be created.
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class is=
=20
> needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would=20
> inherit
> from the same classes its base class inherits from. All constructors woul=
d=20
> work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of Base,=
=20
> to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion operator=
s=20
> can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility were=
=20
> needed,
> one would only need to implement them once, since copying the produced ty=
pe
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
>
> In general the usual rules of `reinterpret_cast` apply to the copied=20
> classes
> with respect to their general classes, exactly as if the copied class had=
=20
> been
> implemented by hand.
>
> ### Overloads ###
>
> Duplicating an existing class should allow for new overloads on the new=
=20
> type,
> and no ambiguity between the copied class, the old class and other copied
> classes.
>
> ```cpp
> class Position : using std::pair<double, double> {};
> class Distance : using std::pair<double, double> {};
>
> Position operator+(const Position & p, const Distance & d) {
> return Position(p.first + d.first, p.second + d.second);
> }
>
> Distance operator+(const Distance & lhs, const Distance & rhs) {
> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
> }
>
> // ...
>
> Position p(1, 1);
> Distance d(1, 1);
>
> p + d; // OK
> d + d; // OK
> p + p; // Error
> ```
>
> ### Templated Class Copy ###
>
> The user might want to create a single templatized copy interface, and us=
e=20
> it
> multiple times. For example, one might want multiple copied classes which=
=20
> can
> convert to their original. This could be done as follows:
>
> ```cpp
> struct A { int x; };
>
> template <typename T>
> struct TemplatizedCopy : using T {
> static_assert(std::is_standard_layout<T>::value,
> "Can't use this with a non-standard-layout class");
>
> operator T&() { return *reinterpret_cast<T*>(this); }
> };
>
> // Could be used either via normal typedefs
> using Copy1 =3D TemplatizedCopy<A>;
>
> // Or via copy, depending on requirements.
> struct Copy2 : using TemplatizedCopy<A> {};
> ```
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating=20
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template parameters=
=20
> than
> the base class. Partial or full specializations of the base class can be=
=20
> allowed:
>
> ```cpp
> template <typename T, typename U>
> struct A {};
>
> template <typename T>
> struct B : using A<T, double> {};
>
> B<int> b;
> ```
>
> When the base class has partial specializations, only those who apply are=
=20
> copied
> to the copied class.
>
> ```cpp
> template <typename T, typename U>
> struct A { T t; U u; };
>
> template <typename U>
> struct A<double, U> { double y; U u; };
>
> template <typename T>
> struct A<T, int> { T t; char z; };
>
> template <typename T>
> struct B : using A<T, double> {};
>
> /* Equivalent to
>
> template <typename T>
> struct B { T t; double u; };
>
> template <>
> struct B<double> { double y; double u; };
>
> */
> ```
>
> The copied class can add additional specializations. Or specializations=
=20
> for a
> given class can copy another.
>
> ```cpp
> template <typename T>
> struct A { int x; };
>
> struct B { char c; };
>
> template <typename T>
> struct C : using A<T> {};
>
> template <>
> struct C<double> : using B {};
>
> template <>
> struct A<int> : using C<double> {};
>
> /* Equivalent to
>
> template<>
> struct A<int> { char c; };
>
> template <typename T>
> struct C { int x; };
>
> template <>
> struct C<double> { char c; };
>
> */
> ```
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because each=
=20
> copy
> would depend on the originals, rather than on the copied classes. A=20
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A;
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal `usin=
g`
> alias directive. `using class` is only valid when the left hand side has=
=20
> been
> defined as a copy of the right hand side.
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
> ### Substituting Existing Functionality (Optional) ###
>
> Ideally one may want to use most of an implementation for another class,=
=20
> but
> vary a certain number of methods. In this case, if `Copy` contains a memb=
er
> function that already exists in `Base`, then that implementation is=20
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of "interface"=
,=20
> where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed also=
=20
> alter
> behavior and/or variable types of non-modified member and non-member=20
> functions,
> since the new behavior could be either erroneous or ambiguous.
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types. Using t=
he
> extension that allows the modification of the copied types, this could=20
> allow for
> creation of numeric types where some operations are disabled as needed.
>
> ```cpp
> struct Id : using int {
> Id operator+(Id, Id) =3D delete;
> Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
> // Defining new operators with the old type can allow interoperativit=
y
> Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden as=
=20
> the
> generated copy is `final` (although it is allowed to keep copying the new=
ly
> created class).
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine=20
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
> Compatibility
> -------------
>
> As the syntax is new, no old code would be affected.
>
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/445876f8-045f-4d35-91ed-662309f8aa85%40isocpp.or=
g.
------=_Part_105_172844348.1482278310449
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I like the basic idea but I think it may get too complicat=
ed if replacements and extensions are allowed. Isn't this what we have =
inheritance for?<div><br></div><div>For the part about interdependent class=
es which need to get copied I think your example violates your rule as thes=
e two classes are dependant in both directions, the rule needs to be more l=
enient when it comes to ordering of declarations.</div><div><br></div><div>=
I think that the most common case of interdependant groups of classes to ge=
t copies will be parent and child classes. Would your idea with a nested &q=
uot;using class C =3D A" cover that case to? I think an example of how=
this would look would be warranted.</div><div><br></div><div>I think that =
making strong typedefs of primitive types is maybe the most important case.=
It does seem very odd to use the keyword 'struct' to achieve this.=
... then again, without thinking too deeply about it I could find no compell=
ing reason that you would not be able to inherit from primitive types. This=
would make the struct keyword more appropriate as you can inherit a struct=
from a primitive type and redefine its functions (which of those are to be=
considered as free or member functions is another issue).</div><div><br></=
div><div>Finally, if you add copy ctors and cast operators to/from the orig=
inal types, doesn't this defy the purpose of the "strong" in =
the typedef? Or do you mean that such cast operators are implicitly explici=
t? My take on this would be that there should probably be explicit conversi=
on possibilities between original and copy unless maybe if you =3D delete t=
hem.</div><div><br><br>Den m=C3=A5ndag 19 december 2016 kl. 12:04:48 UTC+1 =
skrev sval...@gmail.com:<blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div d=
ir=3D"ltr">This is a stub proposal on strong typedefs, i.e. types that work=
in the exact same way, but allow separate overloading. Other papers and pr=
oposals exist, but I've tried a different approach that tries to mimic =
a more inheritance-like syntax which might be more intuitive. The full text=
can be found online at <a href=3D"https://github.com/Svalorzen/CppCopyProp=
osal" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'ht=
tps://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCop=
yProposal\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQ=
KQw';return true;" onclick=3D"this.href=3D'https://www.google.com/u=
rl?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCopyProposal\x26sa\x3dD\x=
26sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQw';return true;"=
>https://github.com/Svalorzen/<wbr>CppCopyProposal.<br><br></a>I'm copy=
ing the text below. Thanks in advance for your comments.<br><br><span style=
=3D"font-family:courier new,monospace">Duplication and Extension of Existin=
g Classes<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D<br><br>Introduction<br>------------<br><br>This document describes a=
possible approach to duplicate existing functionality<br>while wrapping it=
in a new type, without the burden of inheritance and to allow<br>function =
overloads on syntactically identical but semantically different types<br>(a=
lso known as *strong typedef*).<br><br>The approach taken should be simple =
to implement and be applicable to existing<br>code.<br><br>Optional section=
s are to be read as additional ideas that could be further<br>developed or =
completely ignored. They are mostly food for thought, but included<br>for c=
ompleteness.<br><br>Reasons<br>-------<br><br>- Scientific libraries where =
a type has different behaviors depending on context<br>=C2=A0 have currentl=
y no simple way to indicate the semantic differences. Since a<br>=C2=A0 `ty=
pedef` does not allow multiple overloads on new typedef types - since they<=
br>=C2=A0 are still the "old" type - they have to resort to imper=
fect techniques, such<br>=C2=A0 as copying, wrapping or inheriting the need=
ed type. Examples: coordinates in a<br>=C2=A0 plane (rectangular, polar), v=
ectors of double (probabilities, values).<br>- Easier maintainability of co=
de which is known to be the same, rather than<br>=C2=A0 being copy-pasted.<=
br>- Avoiding misuse of inheritance in order to provide a copy-paste altern=
ative.<br>=C2=A0 This can result in very deep hierarchies of types which sh=
ould really not have<br>=C2=A0 anything to do with each other.<br>- Enablin=
g users to use an existing and presumably correct type but partially<br>=C2=
=A0 extend it with context-specific methods. Examples: search for "`st=
d::vector`<br>=C2=A0 inheritance" yields many results of users trying =
to maintain the original<br>=C2=A0 interface and functionality but add one =
or two methods.<br><br>The functionality should have the following requirem=
ents:<br><br>- Can be applied to existing code.<br>- Should limit dependenc=
ies between new and old type as much as possible.<br>- Should allow for par=
tial extensions of the old code.<br><br>Alternatives<br>------------<br><br=
>### Typedef / Using Directive ###<br><br>Using a type alias creates an alt=
ernative name for a single type. However, this<br>leaves no space to implem=
ent overloads that are context-specific. Nor a type can<br>be extended in a=
simple way while keeping the old interface intact.<br><br>### Inheritance =
###<br><br>Inheritance requires redefinition of all constructors, and creat=
es a stricter<br>dependency between two classes than what is proposed here.=
Classes may be<br>converted to a common ancestor even though that is undes=
ired or even dangerous<br>in case of implicit conversions.<br><br>Inheritan=
ce may also be unwanted in order to avoid risks linked to polymorphism<br>a=
nd freeing data structures where the base class does not have a virtual<br>=
destructor.<br><br>### Encapsulation with Manual Exposure of Needed Methods=
###<br><br>This method obviously requires a great deal of code to be rewri=
tten in order to<br>wrap every single method that the old class was exposin=
g.<br><br>In addition one needs to have intimate knowledge of the original =
interface in<br>order to be able to duplicate it correctly. Template method=
s, rvalue references,<br>possibly undocumented methods which are required i=
n order to allow the class to<br>behave in the same way as before. This hei=
ghtens the bar significantly for many<br>users, since they may not know cor=
rectly how to duplicate an interface and how<br>to forward parameters to th=
e old interface correctly.<br><br>The new code also must be maintained in c=
ase the old interface changes.<br><br>### Copying the Base Class ###<br><br=
>This can be useful, but requires all code to be duplicated, and thus<br>si=
gnificantly increases the burden of maintaining the code. All bugs discover=
ed<br>in one class must be fixed in the other class too. All new features a=
pplied to<br>one class must be applied to the other too.<br><br>### Macro-e=
xpansion ###<br><br>Macro expansions can be used in order to encode the int=
erface and implementation<br>of a given class just one time, and used multi=
ple times to produce separate<br>classes.<br><br>This approach is unfortuna=
tely not applicable to existing code, and is very hard<br>to extend if one =
wants to copy a class but add additional functionality to it.<br><br>### Te=
mplates ###<br><br>Templates produce for each instantiation a separate type=
.. They are unfortunately<br>not applicable to previously existing code. For=
new code, they would require the<br>creation of "fake" template =
parameters that would need to vary in order to<br>produce separate types.<b=
r><br>In addition, class extension through templates is not possible: varia=
tions would<br>need to be made through specialization, which itself require=
s copying existing<br>code.<br><br>Previous Work<br>-------------<br><br>St=
rong typedefs have already been proposed for the C++ language multiple time=
s<br>([N1706](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers=
/2004/n1706.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.hre=
f=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc=
1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sntz\x3d1\=
x26usg\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;" onclick=3D"=
this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.o=
rg%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sn=
tz\x3d1\x26usg\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;">htt=
p://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2004/n1706.pdf</a=
>),<br>[N1891](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/paper=
s/2005/n1891.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.hr=
ef=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjt=
c1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26sntz\x3d1=
\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;" onclick=3D=
"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.=
org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26s=
ntz\x3d1\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;">ht=
tp://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2005/n1891.pdf</=
a>),<br>[N3515](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/pape=
rs/2013/n3515.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.h=
ref=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fj=
tc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d=
1\x26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;" onclick=
=3D"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-s=
td.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x=
26sntz\x3d1\x26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;"=
>http://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2013/n3515.pd=
f</a>),<br>[N3741](<a href=3D"https://isocpp.org/files/papers/n3741.pdf)" t=
arget=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'https://w=
ww.google.com/url?q\x3dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pd=
f)\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA'=
;;return true;" onclick=3D"this.href=3D'https://www.google.com/url?q\x3=
dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pdf)\x26sa\x3dD\x26sntz\=
x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA';return true;">https:=
//isocpp.org/<wbr>files/papers/n3741.pdf)</a>). These typedefs are named<br=
>*opaque typedefs*, and these papers try to explore and define exactly the<=
br>behavior that such typedefs should and would have when used to create ne=
w<br>types. In particular, the keywords `public`, `protected` and `private`=
are used<br>in order to create a specific relation with the original type =
and how is the<br>new type allowed to be cast back to the original type or =
be used in its place<br>during overloads.<br><br>This document shares many =
of the the same principles, for example (quoting from<br>N3741):<br><br>>=
; - Consistent with restrictions imposed on analogous relationships such as=
<br>>=C2=A0=C2=A0 base classes underlying derived classes and integer ty=
pes underlying enums,<br>>=C2=A0=C2=A0 an underlying type should be (1) =
complete and (2) not cv-quali=EF=AC=81ed. We also do<br>>=C2=A0=C2=A0 no=
t require that any enum type, reference type, array type, function type, or=
<br>>=C2=A0=C2=A0 pointer-to-member type be allowed as an underlying typ=
e.<br><br>However, this document tries to propose a possibly more simple ap=
proach, where<br>a new language feature is introduced with the same meaning=
and functionality as<br>if the user autonomously implemented a new class h=
im/herself, matching the<br>original type completely. Thus, it should resul=
t for the user more simple to<br>understand (as it simply matches already t=
he already understood mechanics of<br>creating a new, unique type from noth=
ing), and no new rules for type conversion<br>and selection on overloads ha=
ve to be created.<br><br>Syntax<br>------<br><br>### Simple Case ###<br><br=
>Syntax could look something like this:<br><br>```cpp<br>class Base {<br>=
=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Ba=
se() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { s=
td::cout << "foo " << x << "\n"; }<br=
>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
int x;<br>};<br><br>struct Copy : using Base {};<br><br>/* Equivalent to<br=
><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 void foo() { std::cout << "foo " << x <&=
lt; "\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br><br>One cannot co=
py a class and inherit at the same time. If such a class is needed<br>one w=
ould need to create it by hand with the desided functionality and<br>inheri=
ting from the desired classes, as it would be done normally.<br><br>All met=
hod implementations would be the same. The copied class would inherit<br>fr=
om the same classes its base class inherits from. All constructors would wo=
rk<br>in the same way.<br><br>### Adding New Functionality ###<br><br>Ideal=
ly one could specify additional methods, separate from that of Base, to add=
<br>upon the existing functionality.<br><br>```cpp<br>struct Base {<br>=C2=
=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<br>};<=
br><br>struct Derived : public Base {};<br><br>struct Copy : using Base {<b=
r>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<b=
r>};<br><br>struct CopyDerived : using Derived {};<br><br>/* Equivalent to<=
br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << =
"foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << =
"bar\n"; }<br>};<br><br>struct CopyDerived : public Base {};<br><=
br>*/<br>```<br><br>Only new methods need to be implemented for that class.=
<br><br>#### Interfacing with the Original Class ####<br><br>In order to in=
terface with the original class, simple conversion operators can<br>be adde=
d by the user explicitly at-will, in order to obtain the desired<br>interfa=
ce. Note that if more types with this kind of compatibility were needed,<br=
>one would only need to implement them once, since copying the produced typ=
e<br>would copy the new, more compatible interface with it.<br><br>```cpp<b=
r>struct Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struct Copy : usin=
g Base {<br>=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>};=
<br>```<br><br>`reinterpret_cast` may also be used to convert back to the o=
riginal class,<br>limited by the tool's already existing rules.<br><br>=
In general the usual rules of `reinterpret_cast` apply to the copied classe=
s<br>with respect to their general classes, exactly as if the copied class =
had been<br>implemented by hand.<br><br>### Overloads ###<br><br>Duplicatin=
g an existing class should allow for new overloads on the new type,<br>and =
no ambiguity between the copied class, the old class and other copied<br>cl=
asses.<br><br>```cpp<br>class Position : using std::pair<double, double&=
gt; {};<br>class Distance : using std::pair<double, double> {};<br><b=
r>Position operator+(const Position & p, const Distance & d) {<br>=
=C2=A0=C2=A0=C2=A0 return Position(p.first + d.first, p.second + d.second);=
<br>}<br><br>Distance operator+(const Distance & lhs, const Distance &a=
mp; rhs) {<br>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rhs.first, lhs=
..second + rhs.second);<br>}<br><br>// ...<br><br>Position p(1, 1);<br>Dista=
nce d(1, 1);<br><br>p + d; // OK<br>d + d; // OK<br>p + p; // Error<br>```<=
br><br>### Templated Class Copy ###<br><br>The user might want to create a =
single templatized copy interface, and use it<br>multiple times. For exampl=
e, one might want multiple copied classes which can<br>convert to their ori=
ginal. This could be done as follows:<br><br>```cpp<br>struct A { int x; };=
<br><br>template <typename T><br>struct TemplatizedCopy : using T {<b=
r>=C2=A0=C2=A0=C2=A0 static_assert(std::is_<wbr>standard_layout<T>::v=
alue,<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this with a non-st=
andard-layout class");<br><br>=C2=A0=C2=A0=C2=A0 operator T&() { r=
eturn *reinterpret_cast<T*>(this); }<br>};<br><br>// Could be used ei=
ther via normal typedefs<br>using Copy1 =3D TemplatizedCopy<A>;<br><b=
r>// Or via copy, depending on requirements.<br>struct Copy2 : using Templa=
tizedCopy<A> {};<br>```<br><br>### Copying Template Classes ###<br><b=
r>Since the construct is similar to inheritance, the syntax for creating al=
iases<br>of templated classes could be the same:<br><br>```cpp<br>template =
<typename T><br>struct A {};<br><br>template <typename T><br>st=
ruct B : using A<T> {};<br><br>B<int> b;<br>```<br><br>The copi=
ed class must have the same number or less of template parameters than<br>t=
he base class. Partial or full specializations of the base class can be all=
owed:<br><br>```cpp<br>template <typename T, typename U><br>struct A =
{};<br><br>template <typename T><br>struct B : using A<T, double&g=
t; {};<br><br>B<int> b;<br>```<br><br>When the base class has partial=
specializations, only those who apply are copied<br>to the copied class.<b=
r><br>```cpp<br>template <typename T, typename U><br>struct A { T t; =
U u; };<br><br>template <typename U><br>struct A<double, U> { d=
ouble y; U u; };<br><br>template <typename T><br>struct A<T, int&g=
t; { T t; char z; };<br><br>template <typename T><br>struct B : using=
A<T, double> {};<br><br>/* Equivalent to<br><br>template <typenam=
e T><br>struct B { T t; double u; };<br><br>template <><br>struct =
B<double> { double y; double u; };<br><br>*/<br>```<br><br>The copied=
class can add additional specializations. Or specializations for a<br>give=
n class can copy another.<br><br>```cpp<br>template <typename T><br>s=
truct A { int x; };<br><br>struct B { char c; };<br><br>template <typena=
me T><br>struct C : using A<T> {};<br><br>template <><br>str=
uct C<double> : using B {};<br><br>template <><br>struct A<i=
nt> : using C<double> {};<br><br>/* Equivalent to<br><br>template&=
lt;><br>struct A<int> { char c; };<br><br>template <typename T&=
gt;<br>struct C { int x; };<br><br>template <><br>struct C<double&=
gt; { char c; };<br><br>*/<br>```<br><br>### Copying Multiple Dependent Cla=
sses ###<br><br>Copying multiple classes using the simple syntax we have de=
scribed can be<br>impossible if those classes depend on one another. This i=
s because each copy<br>would depend on the originals, rather than on the co=
pied classes. A possible way<br>to specify such dependencies could be:<br><=
br>```cpp<br>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A * a;<br>};=
<br><br>struct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>struct C;<br><br=
>struct D : using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A;<br>};<br><=
br>struct C : using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>};<br=
><br>/* Equivalent to<br><br>struct C;<br><br>struct D {<br>=C2=A0=C2=A0=C2=
=A0 C * a;<br>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<br>};<br><br>=
*/<br>```<br><br>`using class` has been used in order to disambiguate it fr=
om normal `using`<br>alias directive. `using class` is only valid when the =
left hand side has been<br>defined as a copy of the right hand side.<br><br=
>In case of a template base class using a template second class, one could<=
br>specify different copies for certain specializations;<br><br>```cpp<br>t=
emplate <typename T><br>struct A {};<br><br>template <typename T&g=
t;<br>struct B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><br>template =
<typename T><br>struct C : using A<T> {};<br><br>```<br><br>###=
Substituting Existing Functionality (Optional) ###<br><br>Ideally one may =
want to use most of an implementation for another class, but<br>vary a cert=
ain number of methods. In this case, if `Copy` contains a member<br>functio=
n that already exists in `Base`, then that implementation is substituted<br=
>in `Copy`. This may or may not be allowed for attributes.<br><br>```cpp<br=
>struct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "=
foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "=
bar\n"; }<br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=
=A0 void foo() { std::cout << "baz\n"; }<br>};<br><br>/* Eq=
uivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::co=
ut << "baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::co=
ut << "bar\n"; }<br>};<br><br>*/<br>```<br><br>A side effec=
t of this is that it could allow for some type of "interface", wh=
ere<br>some base class could be defined as:<br><br>```cpp<br>struct Base {<=
br>=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 void foo();<=
br>=C2=A0=C2=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : using Base {<=
br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void baz()=
;<br>=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/* Equivalent t=
o<br><br>struct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=
=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<br>};<br><br>=
*/<br><br>struct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=
=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalent to<br><br>=
struct Copy2 {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void=
foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void abc();=
<br>};<br><br>*/<br>```<br><br>This feature could however present problems =
when the members changed also alter<br>behavior and/or variable types of no=
n-modified member and non-member functions,<br>since the new behavior could=
be either erroneous or ambiguous.<br><br>### Copying and Extending Primiti=
ve Types (Optional) ###<br><br>The same syntax could be used in order to ex=
tend primitive types. Using the<br>extension that allows the modification o=
f the copied types, this could allow for<br>creation of numeric types where=
some operations are disabled as needed.<br><br>```cpp<br>struct Id : using=
int {<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete;<br>=C2=A0=C2=
=A0=C2=A0 Id operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 // Non-exp=
licitly deleted operators keep their validity<br><br>=C2=A0=C2=A0=C2=A0 // =
Defining new operators with the old type can allow interoperativity<br>=C2=
=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0 // We can conv=
ert the copied type to the old one.<br>=C2=A0=C2=A0=C2=A0 operator int() { =
return (*this) * 2; }<br>};<br><br>/* Equivalent to<br><br>class Id final {=
<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id rhs) { return =
Id{lhs.v_ - rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id=
operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator=
int() { return v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<br><br>Note that=
when copying from a primitive types inheritance is forbidden as the<br>gen=
erated copy is `final` (although it is allowed to keep copying the newly<br=
>created class).<br><br>### STL Traits (Optional) ###<br><br>Traits could b=
e included in the standard library in order to determine whether a<br>class=
is a copy of another, or if it has been derived from a copy<br>(copies/inh=
eritances could be nested arbitrarily).<br><br>```cpp<br>struct Base {};<br=
><br>struct Copy : using Base {};<br><br>static_assert(std::is_copy<<wbr=
>Copy, Base>::value);<br><br>struct ChildCopy : public Copy {};<br><br>s=
truct CopyChildCopy : using ChildCopy {};<br><br>static_assert(std::is_copy=
_<wbr>base_of<Base, CopyChildCopy>::value);<br>```<br><br>Compatibili=
ty<br>-------------<br><br>As the syntax is new, no old code would be affec=
ted.<br></span><br></div></blockquote></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/445876f8-045f-4d35-91ed-662309f8aa85%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/445876f8-045f-4d35-91ed-662309f8aa85=
%40isocpp.org</a>.<br />
------=_Part_105_172844348.1482278310449--
------=_Part_104_208211713.1482278310447--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Wed, 21 Dec 2016 10:03:04 +0100
Raw View
--047d7b4507debb9a2d0544276bd1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hi,
This is an interesting proposal.
May I suggest you change your "copy" word usage for something else or more
detailed?
"Copy" operation already have a meaning when manipulating objects,
"Template" is obviously already taken too,
So maybe something like "code-copy" or "type-copy" or something like that
would fit best.
My main question while reading this proposal:
What happen if the original type have a hidden implementation?
That is:
class A {
class Impl;
Impl* pimpl;
public:
A();.
Impl* fork();
};
class B : using C {};
Assuming A's functions are defined in another translation unit which is
already compiled (for example a shared library file):
1. Is this allowed by your proposal?
2. If yes, what is the type of B::Impl? A typedef of A::Impl?
3. Do you propose that nested types be implicitly type-copied too?
Then:
4. I'm also concerned by symbol export/import in these cases. Even if not
defined by the standard, if the feature have strong limitations when
importing/exporting symbols, it might become a no-go proposal.
5. What about class specifiers like alignof/alignas? Are they maintained?
How would one remove them?
6. Would there be a way to remove types and typedefs from the original type=
?
Just wondering, not a feature request.
Jo=C3=ABl Lamotte.
Sent from mobile.
On Dec 20, 2016 7:02 PM, "Eugenio Bargiacchi" <svalorzen@gmail.com> wrote:
> I'm not sure you can `static_cast` between pointers of unrelated classes
> (I think not actually). `reinterpret_cast` is also very limited in what i=
t
> can do in this case: I'm not 100% sure on the details, but in general I
> think it is allowed only when the two classes are `standard_layout` (whic=
h
> has a bunch of restrictions).
>
> In any case, please note that `reinterpret_cast` is used as an example,
> and it would still keep all already existing rules with no modifications,
> as this proposal does not even try to go there. How an user would like to
> use the feature and define additional methods is his/her concern. In term=
s
> of the proposal, all cpp features work as if the user had implemented the
> new class by hand, so no new rules have to be introduced.
>
> On Tue, Dec 20, 2016 at 6:49 PM, D. B. <db0451@gmail.com> wrote:
>
>> A quick comment on one thing that stuck out to me while skimming. For no=
w
>> I'll leave the real review to those with more time/experience.
>>
>> Is reinterpret_cast really the correct tool for this? It seems to me
>> like static_cast would be more appropriate.
>>
>> Think int vs enum class. The types are not implicitly substitutable but
>> are *really* the same, or at least sub/supersets... sound familiar? So
>> an explicit static_cast should be safe and preferable, by my understandi=
ng.
>>
>> To me reinterpret_cast signals (screams) 'I probably shouldn't be doing
>> this, but there's no other way, and I promise this pointer/reference was
>> originally (compatible with) what I'm saying it is... honest'.
>>
>> --
>> 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/is
>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7
>> UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGN=
ADMd0orere%3DYZ2_y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3De=
mail&utm_source=3Dfooter>
>> .
>>
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW32
> x0pGggvMP%3DFOY8xQ%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
sw7zmU8iz7Ysc3e7cpvf3GdrZW32x0pGggvMP%3DFOY8xQ%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOU91OPx4SQ_dLiHnpmXXqj69n7tW%3DOwOb60dXksnWWt8=
UjViA%40mail.gmail.com.
--047d7b4507debb9a2d0544276bd1
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"auto">Hi,<div dir=3D"auto">This is an interesting proposal.</di=
v><div dir=3D"auto">May I suggest you change your "copy" word usa=
ge for something else or more detailed?</div><div dir=3D"auto">"Copy&q=
uot; operation already have a meaning when manipulating objects,</div><div =
dir=3D"auto">"Template" is obviously already taken too,</div><div=
dir=3D"auto"><br></div><div dir=3D"auto">So maybe something like "cod=
e-copy" or "type-copy" or something like that would fit best=
..</div><div dir=3D"auto"><br></div><div dir=3D"auto">My main question while=
reading this proposal:</div><div dir=3D"auto">What happen if the original =
type have a hidden implementation?</div><div dir=3D"auto">That is:</div><di=
v dir=3D"auto"><br></div><div dir=3D"auto"><br></div><div dir=3D"auto">=C2=
=A0 =C2=A0 class A {</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =C2=A0 cla=
ss Impl;=C2=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =C2=A0 Impl* pim=
pl;=C2=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 public:</div><div dir=3D"aut=
o">=C2=A0 =C2=A0 =C2=A0 =C2=A0 A();. =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div=
><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =C2=A0 Impl* fork();</div><div dir=
=3D"auto">=C2=A0 =C2=A0 =C2=A0};</div><div dir=3D"auto">=C2=A0</div><div di=
r=3D"auto">=C2=A0 =C2=A0 =C2=A0class B : using C {};</div><div dir=3D"auto"=
><br></div><div dir=3D"auto">Assuming A's functions are defined in anot=
her translation unit which is already compiled (for example a shared librar=
y file):</div><div dir=3D"auto"><br></div><div dir=3D"auto">1. Is this allo=
wed by your proposal?</div><div dir=3D"auto">2. If yes, what is the type of=
B::Impl? A typedef of A::Impl?=C2=A0</div><div dir=3D"auto">3. Do you prop=
ose that nested types be implicitly type-copied too?</div><div dir=3D"auto"=
><br></div><div dir=3D"auto">Then:</div><div dir=3D"auto"><br></div><div di=
r=3D"auto">4. I'm also concerned by symbol export/import in these cases=
.. Even if not defined by the standard, if the feature have strong limitatio=
ns when importing/exporting symbols, it might become a no-go proposal.</div=
><div dir=3D"auto"><br></div><div dir=3D"auto"><br></div><div dir=3D"auto">=
5. What about class specifiers like alignof/alignas? Are they maintained? H=
ow would one remove them?</div><div dir=3D"auto"><br></div><div dir=3D"auto=
">6. Would there be a way to remove types and typedefs from the original ty=
pe?</div><div dir=3D"auto">Just wondering, not a feature request.</div><div=
dir=3D"auto"><br></div><div dir=3D"auto">Jo=C3=ABl Lamotte.</div><div dir=
=3D"auto"><br></div><div dir=3D"auto">=C2=A0</div><div dir=3D"auto">=C2=A0<=
/div><div dir=3D"auto"><br></div><div dir=3D"auto"><br></div><div dir=3D"au=
to"><br><br><div data-smartmail=3D"gmail_signature" dir=3D"auto">Sent from =
mobile.</div></div></div><div class=3D"gmail_extra"><br><div class=3D"gmail=
_quote">On Dec 20, 2016 7:02 PM, "Eugenio Bargiacchi" <<a href=
=3D"mailto:svalorzen@gmail.com">svalorzen@gmail.com</a>> wrote:<br type=
=3D"attribution"><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I'=
;m not sure you can `static_cast` between pointers of unrelated classes (I =
think not actually). `reinterpret_cast` is also very limited in what it can=
do in this case: I'm not 100% sure on the details, but in general I th=
ink it is allowed only when the two classes are `standard_layout` (which ha=
s a bunch of restrictions).<br><br></div>In any case, please note that `rei=
nterpret_cast` is used as an example, and it would still keep all already e=
xisting rules with no modifications, as this proposal does not even try to =
go there. How an user would like to use the feature and define additional m=
ethods is his/her concern. In terms of the proposal, all cpp features work =
as if the user had implemented the new class by hand, so no new rules have =
to be introduced.<br></div><div class=3D"gmail_extra"><br><div class=3D"gma=
il_quote">On Tue, Dec 20, 2016 at 6:49 PM, D. B. <span dir=3D"ltr"><<a h=
ref=3D"mailto:db0451@gmail.com" target=3D"_blank">db0451@gmail.com</a>><=
/span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>A qui=
ck comment on one thing that stuck out to me while skimming. For now I'=
ll leave the real review to those with more time/experience.<br><br></div>I=
s <font face=3D"monospace,monospace">reinterpret_cast<font face=3D"arial,he=
lvetica,sans-serif"> really the correct tool for this? It seems to me like =
<font face=3D"monospace,monospace">static_cast <font face=3D"arial,helvetic=
a,sans-serif">would be more appropriate.<br><br>Think <span style=3D"font-f=
amily:monospace,monospace">int </span>vs <span style=3D"font-family:monospa=
ce,monospace">enum class</span>. The types are not implicitly substitutable=
but are <i>really</i> the same, or at least sub/supersets... sound familia=
r? So an explicit static_cast should be safe and preferable, by my understa=
nding.<br><br>To me <font face=3D"monospace,monospace">reinterpret_cast<fon=
t face=3D"arial,helvetica,sans-serif"> signals (screams) 'I probably sh=
ouldn't be doing this, but there's no other way, and I promise this=
pointer/reference was originally (compatible with) what I'm saying it =
is... honest'.</font></font></font></font></font></font><br></div><span=
>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU=
5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CACGiwhHGNADMd0orere%3DYZ2_y7<wbr>UB8Y0MPU5p25d1fE8i2WKrpA=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW=
32x0pGggvMP%3DFOY8xQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Df=
ooter" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgi=
d/std-<wbr>proposals/CAHfn%3D%<wbr>2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW32<wbr>x0pGg=
gvMP%3DFOY8xQ%40mail.<wbr>gmail.com</a>.<br>
</blockquote></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OPx4SQ_dLiHnpmXXqj69n7tW%3DOwOb=
60dXksnWWt8UjViA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OPx4SQ_dL=
iHnpmXXqj69n7tW%3DOwOb60dXksnWWt8UjViA%40mail.gmail.com</a>.<br />
--047d7b4507debb9a2d0544276bd1--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Wed, 21 Dec 2016 13:41:28 +0100
Raw View
--001a1143b094cc480405442a786b
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Bengt, I understand it may get a bit complicated. Replacements are actually
a feature that I proposed just to get it considered. I believe the feature
should allow to add new methods/features to a class; substituting/deleting
existing functionality is more complicated but it could have its use cases
and would allow to make better use of existing class implementations, so
that's why I added it for considerations.
About the part on interdependent classes I have written that the classes
should be "defined" as copies of their aliased equivalent. Not sure if the
compiler can handle it in one pass, or if there is a better way to state
that requirement.
I believe that making strong typedefs in general is important, and not only
for primitive types. Sure making them on primitive types only would still
be an improvement, but there are many compelling use-cases for also making
strong typedefs of classes, for example in scientific fields.
I have added in my examples copy constructors and the like since they are
considered heavily in the already existing proposals, and they state that
requirements were gathered after extensive discussions with many potential
users. It's definitely not a requirement to add them, I just wanted to show
how it could be done since it could be needed.
Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
terminology.
About internal classes, this is a very good question. Actually I realized
yesterday that another thing which could be hard to define correctly would
be how to treat `friend` declarations. A relatively simple solution would
be that all names that depend on the original name are copied, while those
that don't are not ported over (for example friend method
declarations/definitions).
So in your example A::Impl would be copied into B::Impl. However, in this
example:
void bar() {}
struct A {
friend int foo(A) { return 0; }
friend void bar();
};
struct B : using A {};
Nothing would be copied, since the functions `foo` and `bar` do not depend
directly on the original type. If needed, a different `int foo(B)` can be
separately implemented by the copier. It's not exactly intuitive, but I
believe it would be better, otherwise copying everything defined
"internally" could lead to recursive copying of many things which one would
not expect copied.
About symbols, personally I think they should work as if the user had
written the new class by hand, if possible. This should keep the rules
relatively simple, as a user can always create a new copy of a class by
hand (one cannot do inheritance by hand, for example, as the language gives
guarantees about it not achievable by writing a new class from scratch).
I would say alignof/as would be kept. The same for existing typedefs. The
idea here is to offer a certain amount of customizations of classes that
are copied, but not too much - otherwise it would be best for the user to
just create the new type by hand. The line must be drawn somewhere, and I'd
prefer the feature to be simple rather than having to define how to take
apart an existing type. Ideally the feature would be more constructive than
destructive, as in first define types, and each copy adds stuff, rather
than start with a big type and remove things from it. Having the
possibility to remove things however gives space to make better use of
existing classes, and that's why I included it.
Best,
Eugenio
On Wed, Dec 21, 2016 at 10:03 AM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail.=
com>
wrote:
> Hi,
> This is an interesting proposal.
> May I suggest you change your "copy" word usage for something else or mor=
e
> detailed?
> "Copy" operation already have a meaning when manipulating objects,
> "Template" is obviously already taken too,
>
> So maybe something like "code-copy" or "type-copy" or something like that
> would fit best.
>
> My main question while reading this proposal:
> What happen if the original type have a hidden implementation?
> That is:
>
>
> class A {
> class Impl;
> Impl* pimpl;
> public:
> A();.
> Impl* fork();
> };
>
> class B : using C {};
>
> Assuming A's functions are defined in another translation unit which is
> already compiled (for example a shared library file):
>
> 1. Is this allowed by your proposal?
> 2. If yes, what is the type of B::Impl? A typedef of A::Impl?
> 3. Do you propose that nested types be implicitly type-copied too?
>
> Then:
>
> 4. I'm also concerned by symbol export/import in these cases. Even if not
> defined by the standard, if the feature have strong limitations when
> importing/exporting symbols, it might become a no-go proposal.
>
>
> 5. What about class specifiers like alignof/alignas? Are they maintained?
> How would one remove them?
>
> 6. Would there be a way to remove types and typedefs from the original
> type?
> Just wondering, not a feature request.
>
> Jo=C3=ABl Lamotte.
>
>
>
>
>
>
>
> Sent from mobile.
>
> On Dec 20, 2016 7:02 PM, "Eugenio Bargiacchi" <svalorzen@gmail.com> wrote=
:
>
>> I'm not sure you can `static_cast` between pointers of unrelated classes
>> (I think not actually). `reinterpret_cast` is also very limited in what =
it
>> can do in this case: I'm not 100% sure on the details, but in general I
>> think it is allowed only when the two classes are `standard_layout` (whi=
ch
>> has a bunch of restrictions).
>>
>> In any case, please note that `reinterpret_cast` is used as an example,
>> and it would still keep all already existing rules with no modifications=
,
>> as this proposal does not even try to go there. How an user would like t=
o
>> use the feature and define additional methods is his/her concern. In ter=
ms
>> of the proposal, all cpp features work as if the user had implemented th=
e
>> new class by hand, so no new rules have to be introduced.
>>
>> On Tue, Dec 20, 2016 at 6:49 PM, D. B. <db0451@gmail.com> wrote:
>>
>>> A quick comment on one thing that stuck out to me while skimming. For
>>> now I'll leave the real review to those with more time/experience.
>>>
>>> Is reinterpret_cast really the correct tool for this? It seems to me
>>> like static_cast would be more appropriate.
>>>
>>> Think int vs enum class. The types are not implicitly substitutable but
>>> are *really* the same, or at least sub/supersets... sound familiar? So
>>> an explicit static_cast should be safe and preferable, by my understand=
ing.
>>>
>>> To me reinterpret_cast signals (screams) 'I probably shouldn't be doing
>>> this, but there's no other way, and I promise this pointer/reference wa=
s
>>> originally (compatible with) what I'm saying it is... honest'.
>>>
>>> --
>>> 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/is
>>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>>> To unsubscribe from this group and all its topics, send an email to
>>> std-proposals+unsubscribe@isocpp.org.
>>> To post to this group, send email to std-proposals@isocpp.org.
>>> To view this discussion on the web visit https://groups.google.com/a/is
>>> ocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7
>>> UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com
>>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhHG=
NADMd0orere%3DYZ2_y7UB8Y0MPU5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3D=
email&utm_source=3Dfooter>
>>> .
>>>
>>
>> --
>> You received this message because you are subscribed to the Google Group=
s
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n
>> email to std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cp
>> vf3GdrZW32x0pGggvMP%3DFOY8xQ%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2=
Bsw7zmU8iz7Ysc3e7cpvf3GdrZW32x0pGggvMP%3DFOY8xQ%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
>> .
>>
> --
> 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/is
> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/is
> ocpp.org/d/msgid/std-proposals/CAOU91OPx4SQ_dLiHnpmXXqj69n7t
> W%3DOwOb60dXksnWWt8UjViA%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OPx4S=
Q_dLiHnpmXXqj69n7tW%3DOwOb60dXksnWWt8UjViA%40mail.gmail.com?utm_medium=3Dem=
ail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BstH4eSm5FxQXT%2Barev9QDnni0P8SSwGRh8a=
XLrhmQx7w%40mail.gmail.com.
--001a1143b094cc480405442a786b
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div><div><div><div><div><div><div>Bengt, I understan=
d it may get a bit complicated. Replacements are actually a feature that I =
proposed just to get it considered. I believe the feature should allow to a=
dd new methods/features to a class; substituting/deleting existing function=
ality is more complicated but it could have its use cases and would allow t=
o make better use of existing class implementations, so that's why I ad=
ded it for considerations.<br><br></div>About the part on interdependent cl=
asses I have written that the classes should be "defined" as copi=
es of their aliased equivalent. Not sure if the compiler can handle it in o=
ne pass, or if there is a better way to state that requirement.<br><br></di=
v>I believe that making strong typedefs in general is important, and not on=
ly for primitive types. Sure making them on primitive types only would stil=
l be an improvement, but there are many compelling use-cases for also makin=
g strong typedefs of classes, for example in scientific fields.<br><br></di=
v>I have added in my examples copy constructors and the like since they are=
considered heavily in the already existing proposals, and they state that =
requirements were gathered after extensive discussions with many potential =
users. It's definitely not a requirement to add them, I just wanted to =
show how it could be done since it could be needed.<br><b><br></b></div>Jo<=
span class=3D"m_-6092875754422023223gmail-_Tgc">=C3=ABl, about copy I feel =
the same way. I'll try to work out a nicer terminology.<br><br>About in=
ternal classes, this is a very good question. Actually I realized yesterday=
that another thing which could be hard to define correctly would be how to=
treat `friend` declarations. A relatively simple solution would be that al=
l names that depend on the original name are copied, while those that don&#=
39;t are not ported over (for example friend method declarations/definition=
s).<br><br></span></div><span class=3D"m_-6092875754422023223gmail-_Tgc">So=
in your example A::Impl would be copied into B::Impl. However, in this exa=
mple:<br><br></span></div><div><span class=3D"m_-6092875754422023223gmail-_=
Tgc">void bar() {}<br><br></span></div><span class=3D"m_-609287575442202322=
3gmail-_Tgc">struct A {<br></span></div><span class=3D"m_-60928757544220232=
23gmail-_Tgc">=C2=A0=C2=A0=C2=A0 friend int foo(A) { return 0; }<br></span>=
</div><span class=3D"m_-6092875754422023223gmail-_Tgc">=C2=A0=C2=A0=C2=A0 f=
riend void bar();<br></span><div><div><div><span class=3D"m_-60928757544220=
23223gmail-_Tgc">};<br><br></span></div><div><span class=3D"m_-609287575442=
2023223gmail-_Tgc">struct B : using A {};<br><br></span></div><div><span cl=
ass=3D"m_-6092875754422023223gmail-_Tgc">Nothing would be copied, since the=
functions `foo` and `bar` do not depend directly on the original type. If =
needed, a different `int foo(B)` can be separately implemented by the copie=
r. It's not exactly intuitive, but I believe it would be better, otherw=
ise copying everything defined "internally" could lead to recursi=
ve copying of many things which one would not expect copied.<br><br></span>=
</div><div><span class=3D"m_-6092875754422023223gmail-_Tgc">About symbols, =
personally I think they should work as if the user had written the new clas=
s by hand, if possible. This should keep the rules relatively simple, as a =
user can always create a new copy of a class by hand (one cannot do inherit=
ance by hand, for example, as the language gives guarantees about it not ac=
hievable by writing a new class from scratch). <br><br></span></div><div><s=
pan class=3D"m_-6092875754422023223gmail-_Tgc">I would say alignof/as would=
be kept. The same for existing typedefs. The idea here is to offer a certa=
in amount of customizations of classes that are copied, but not too much - =
otherwise it would be best for the user to just create the new type by hand=
.. The line must be drawn somewhere, and I'd prefer the feature to be si=
mple rather than having to define how to take apart an existing type. Ideal=
ly the feature would be more constructive than destructive, as in first def=
ine types, and each copy adds stuff, rather than start with a big type and =
remove things from it. Having the possibility to remove things however give=
s space to make better use of existing classes, and that's why I includ=
ed it.<br><br></span></div><div><span class=3D"m_-6092875754422023223gmail-=
_Tgc">Best,<br></span></div><div><span class=3D"m_-6092875754422023223gmail=
-_Tgc">Eugenio<br></span></div></div></div><div class=3D"gmail_extra"><br><=
div class=3D"gmail_quote">On Wed, Dec 21, 2016 at 10:03 AM, Klaim - Jo=C3=
=ABl Lamotte <span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.com" tar=
get=3D"_blank">mjklaim@gmail.com</a>></span> wrote:<br><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"auto">Hi,<div dir=3D"auto">This is an interesting=
proposal.</div><div dir=3D"auto">May I suggest you change your "copy&=
quot; word usage for something else or more detailed?</div><div dir=3D"auto=
">"Copy" operation already have a meaning when manipulating objec=
ts,</div><div dir=3D"auto">"Template" is obviously already taken =
too,</div><div dir=3D"auto"><br></div><div dir=3D"auto">So maybe something =
like "code-copy" or "type-copy" or something like that =
would fit best.</div><div dir=3D"auto"><br></div><div dir=3D"auto">My main =
question while reading this proposal:</div><div dir=3D"auto">What happen if=
the original type have a hidden implementation?</div><div dir=3D"auto">Tha=
t is:</div><div dir=3D"auto"><br></div><div dir=3D"auto"><br></div><div dir=
=3D"auto">=C2=A0 =C2=A0 class A {</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 class Impl;=C2=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 Impl* pimpl;=C2=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 public:</div=
><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =C2=A0 A();. =C2=A0 =C2=A0 =C2=A0 =
=C2=A0=C2=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0 =C2=A0 Impl* fork(=
);</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0};</div><div dir=3D"auto">=C2=
=A0</div><div dir=3D"auto">=C2=A0 =C2=A0 =C2=A0class B : using C {};</div><=
div dir=3D"auto"><br></div><div dir=3D"auto">Assuming A's functions are=
defined in another translation unit which is already compiled (for example=
a shared library file):</div><div dir=3D"auto"><br></div><div dir=3D"auto"=
>1. Is this allowed by your proposal?</div><div dir=3D"auto">2. If yes, wha=
t is the type of B::Impl? A typedef of A::Impl?=C2=A0</div><div dir=3D"auto=
">3. Do you propose that nested types be implicitly type-copied too?</div><=
div dir=3D"auto"><br></div><div dir=3D"auto">Then:</div><div dir=3D"auto"><=
br></div><div dir=3D"auto">4. I'm also concerned by symbol export/impor=
t in these cases. Even if not defined by the standard, if the feature have =
strong limitations when importing/exporting symbols, it might become a no-g=
o proposal.</div><div dir=3D"auto"><br></div><div dir=3D"auto"><br></div><d=
iv dir=3D"auto">5. What about class specifiers like alignof/alignas? Are th=
ey maintained? How would one remove them?</div><div dir=3D"auto"><br></div>=
<div dir=3D"auto">6. Would there be a way to remove types and typedefs from=
the original type?</div><div dir=3D"auto">Just wondering, not a feature re=
quest.</div><div dir=3D"auto"><br></div><div dir=3D"auto">Jo=C3=ABl Lamotte=
..</div><div dir=3D"auto"><br></div><div dir=3D"auto">=C2=A0</div><div dir=
=3D"auto">=C2=A0</div><div dir=3D"auto"><br></div><div dir=3D"auto"><br></d=
iv><div dir=3D"auto"><br><br><div data-smartmail=3D"gmail_signature" dir=3D=
"auto">Sent from mobile.</div></div></div><div class=3D"gmail_extra"><br><d=
iv class=3D"gmail_quote"><div><div class=3D"m_-6092875754422023223h5">On De=
c 20, 2016 7:02 PM, "Eugenio Bargiacchi" <<a href=3D"mailto:sv=
alorzen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a>> wrote:<br =
type=3D"attribution"></div></div><blockquote class=3D"gmail_quote" style=3D=
"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div c=
lass=3D"m_-6092875754422023223h5"><div dir=3D"ltr"><div>I'm not sure yo=
u can `static_cast` between pointers of unrelated classes (I think not actu=
ally). `reinterpret_cast` is also very limited in what it can do in this ca=
se: I'm not 100% sure on the details, but in general I think it is allo=
wed only when the two classes are `standard_layout` (which has a bunch of r=
estrictions).<br><br></div>In any case, please note that `reinterpret_cast`=
is used as an example, and it would still keep all already existing rules =
with no modifications, as this proposal does not even try to go there. How =
an user would like to use the feature and define additional methods is his/=
her concern. In terms of the proposal, all cpp features work as if the user=
had implemented the new class by hand, so no new rules have to be introduc=
ed.<br></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On T=
ue, Dec 20, 2016 at 6:49 PM, D. B. <span dir=3D"ltr"><<a href=3D"mailto:=
db0451@gmail.com" target=3D"_blank">db0451@gmail.com</a>></span> wrote:<=
br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left=
:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>A quick comment on =
one thing that stuck out to me while skimming. For now I'll leave the r=
eal review to those with more time/experience.<br><br></div>Is <font face=
=3D"monospace,monospace">reinterpret_cast<font face=3D"arial,helvetica,sans=
-serif"> really the correct tool for this? It seems to me like <font face=
=3D"monospace,monospace">static_cast <font face=3D"arial,helvetica,sans-ser=
if">would be more appropriate.<br><br>Think <span style=3D"font-family:mono=
space,monospace">int </span>vs <span style=3D"font-family:monospace,monospa=
ce">enum class</span>. The types are not implicitly substitutable but are <=
i>really</i> the same, or at least sub/supersets... sound familiar? So an e=
xplicit static_cast should be safe and preferable, by my understanding.<br>=
<br>To me <font face=3D"monospace,monospace">reinterpret_cast<font face=3D"=
arial,helvetica,sans-serif"> signals (screams) 'I probably shouldn'=
t be doing this, but there's no other way, and I promise this pointer/r=
eference was originally (compatible with) what I'm saying it is... hone=
st'.</font></font></font></font></font></font><br></div><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhHGNADMd0orere%3DYZ2_y7UB8Y0MPU=
5p25d1fE8i2WKrpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CACGiwhHGNADMd0orere%3DYZ2_y7<wbr>UB8Y0MPU5p25d1fE8i2WKrpA=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br></div></div>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<span><br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cpvf3GdrZW=
32x0pGggvMP%3DFOY8xQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Df=
ooter" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgi=
d/std-proposals<wbr>/CAHfn%3D%2Bsw7zmU8iz7Ysc3e7cp<wbr>vf3GdrZW32x0pGggvMP%=
3DFOY8xQ%4<wbr>0mail.gmail.com</a>.<br>
</blockquote></div></div><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OPx4SQ_dLiHnpmXXqj69n7tW%3DOwOb=
60dXksnWWt8UjViA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CAOU91OPx4SQ_dLiHnpmXXqj69n7t<wbr>W%3DOwOb60dXksnWWt8UjViA=
%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BstH4eSm5FxQXT%2Barev9QDnni=
0P8SSwGRh8aXLrhmQx7w%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
stH4eSm5FxQXT%2Barev9QDnni0P8SSwGRh8aXLrhmQx7w%40mail.gmail.com</a>.<br />
--001a1143b094cc480405442a786b--
.
Author: Tom Honermann <tom@honermann.net>
Date: Wed, 21 Dec 2016 08:40:12 -0500
Raw View
This is a multi-part message in MIME format.
--------------655914260F8A504BFDBF616A
Content-Type: text/plain; charset=UTF-8; format=flowed
On 12/19/2016 06:04 AM, svalorzen@gmail.com wrote:
> struct Base {};
>
> struct Copy : using Base {};
This syntax was proposed in P0352R0 [1] as part of an alternate
operator.() feature and received favorable review from EWG. I find the
semantics proposed in P0352R0 to be a better use of this syntax.
Tom.
[1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0352r0.pdf
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-e7f3-0dc8aeea22fb%40honermann.net.
--------------655914260F8A504BFDBF616A
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">On 12/19/2016 06:04 AM,
<a class=3D"moz-txt-link-abbreviated" href=3D"mailto:svalorzen@gmail.=
com">svalorzen@gmail.com</a> wrote:<br>
</div>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
struct
Base {};<br>
<br>
struct Copy : using Base {};</span></div>
</blockquote>
<br>
This syntax was proposed in P0352R0 [1] as part of an alternate
operator.() feature and received favorable review from EWG.=C2=A0 I fin=
d
the semantics proposed in P0352R0 to be a better use of this syntax.<br=
>
<br>
Tom.<br>
<br>
[1]:
<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2016/p0352r0.pdf">http://www.open-std.org/jtc1/sc22/=
wg21/docs/papers/2016/p0352r0.pdf</a><br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-e7f3-0dc8aeea22fb%=
40honermann.net?utm_medium=3Demail&utm_source=3Dfooter">https://groups.goog=
le.com/a/isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-e7f3-0dc8aeea2=
2fb%40honermann.net</a>.<br />
--------------655914260F8A504BFDBF616A--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Wed, 21 Dec 2016 15:21:02 +0100
Raw View
--94eb2c04c8e2de526b05442bdcc0
Content-Type: text/plain; charset=UTF-8
I didn't know of that paper. I suppose in case the syntax keyword could be
changed, perhaps `struct Copy : default Base {}`? Or some alternative
punctuation other than a single ':' could be used between the two classes.
On Wed, Dec 21, 2016 at 2:40 PM, Tom Honermann <tom@honermann.net> wrote:
> On 12/19/2016 06:04 AM, svalorzen@gmail.com wrote:
>
> struct Base {};
>
> struct Copy : using Base {};
>
>
> This syntax was proposed in P0352R0 [1] as part of an alternate
> operator.() feature and received favorable review from EWG. I find the
> semantics proposed in P0352R0 to be a better use of this syntax.
>
> Tom.
>
> [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0352r0.pdf
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-
> e7f3-0dc8aeea22fb%40honermann.net
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-e7f3-0dc8aeea22fb%40honermann.net?utm_medium=email&utm_source=footer>
> .
>
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BuZeEA-CA3WzCCLb9Pism47%2B9hkxgPF-VtGxDiUp6H8JA%40mail.gmail.com.
--94eb2c04c8e2de526b05442bdcc0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I didn't know of that paper. I suppose in case the syn=
tax keyword could be changed, perhaps `struct Copy : default Base {}`? Or s=
ome alternative punctuation other than a single ':' could be used b=
etween the two classes.<br></div><div class=3D"gmail_extra"><br><div class=
=3D"gmail_quote">On Wed, Dec 21, 2016 at 2:40 PM, Tom Honermann <span dir=
=3D"ltr"><<a href=3D"mailto:tom@honermann.net" target=3D"_blank">tom@hon=
ermann.net</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span class=3D"">
<div class=3D"m_3467795494696509770moz-cite-prefix">On 12/19/2016 06:04=
AM,
<a class=3D"m_3467795494696509770moz-txt-link-abbreviated" href=3D"ma=
ilto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a> wrote:<=
br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">st=
ruct
Base {};<br>
<br>
struct Copy : using Base {};</span></div>
</blockquote>
<br></span>
This syntax was proposed in P0352R0 [1] as part of an alternate
operator.() feature and received favorable review from EWG.=C2=A0 I fin=
d
the semantics proposed in P0352R0 to be a better use of this syntax.<br=
>
<br>
Tom.<br>
<br>
[1]:
<a class=3D"m_3467795494696509770moz-txt-link-freetext" href=3D"http://=
www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0352r0.pdf" target=3D"_bl=
ank">http://www.open-std.org/jtc1/<wbr>sc22/wg21/docs/papers/2016/<wbr>p035=
2r0.pdf</a><br>
</div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/73728cbb-8905-31ef-e7f3-0dc8aeea22fb%=
40honermann.net?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/7=
3728cbb-8905-31ef-<wbr>e7f3-0dc8aeea22fb%40honermann.<wbr>net</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BuZeEA-CA3WzCCLb9Pism47%2B9=
hkxgPF-VtGxDiUp6H8JA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
uZeEA-CA3WzCCLb9Pism47%2B9hkxgPF-VtGxDiUp6H8JA%40mail.gmail.com</a>.<br />
--94eb2c04c8e2de526b05442bdcc0--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Wed, 21 Dec 2016 19:12:38 +0100
Raw View
--001a11443c3a1d1fae05442f1999
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
wrote:
> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
> terminology.
>
Maybe use "clone-type" or something like that?
Anyway yeah even for functions overloading there is always the same problem
with any kind of strong typedef:
class A {};
class B : using/cloning A {};
void foo(A& a);
Here your proposal suggests that foo() cannot be used with B.
But maybe we want that to be possible?
Add a way to clone free functions too? How about allowing all operations
from A to B?
Also isn't there a risk of member access?
class A {
int hidden_value;
public:
A();
};
class B : using/cloning A
{
public:
int cheat() { return hidden_value; }
};
This looks necessary but a bit problematic also. Apparently Modules
wouldn't change a thing as long
as type members are all considered exported.
Jo=C3=ABl Lamotte
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6A=
Ag_tw%40mail.gmail.com.
--001a11443c3a1d1fae05442f1999
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">=
On 21 December 2016 at 13:41, Eugenio Bargiacchi <span dir=3D"ltr"><<a h=
ref=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a=
>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 =
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Jo<span class=3D=
"m_2157231802647884575m_-6092875754422023223gmail-_Tgc">=C3=ABl, about copy=
I feel the same way. I'll try to work out a nicer terminology.</span><=
/div></blockquote></div><br>Maybe use "clone-type" or something l=
ike that?</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_ext=
ra">Anyway yeah even for functions overloading there is always the same pro=
blem with any kind of strong typedef:</div><div class=3D"gmail_extra"><br><=
/div><div class=3D"gmail_extra">class A {};</div><div class=3D"gmail_extra"=
>class B : using/cloning A {};</div><div class=3D"gmail_extra"><br></div><d=
iv class=3D"gmail_extra">void foo(A& a);</div><div class=3D"gmail_extra=
"><br></div><div class=3D"gmail_extra">Here your proposal suggests that foo=
() cannot be used with B.</div><div class=3D"gmail_extra">But maybe we want=
that to be possible?</div><div class=3D"gmail_extra">Add a way to clone fr=
ee functions too? How about allowing all operations from A to B?</div><div =
class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Also isn't t=
here a risk of member access?</div><div class=3D"gmail_extra"><br></div><di=
v class=3D"gmail_extra">class A {=C2=A0</div><div class=3D"gmail_extra">=C2=
=A0 =C2=A0 int hidden_value;=C2=A0</div><div class=3D"gmail_extra">=C2=A0 p=
ublic:</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 A();</div><div =
class=3D"gmail_extra">};</div><div class=3D"gmail_extra"><br></div><div cla=
ss=3D"gmail_extra">class B : using/cloning A</div><div class=3D"gmail_extra=
">{</div><div class=3D"gmail_extra">public:</div><div class=3D"gmail_extra"=
><br></div><div class=3D"gmail_extra">=C2=A0 =C2=A0int cheat() { return hid=
den_value; }</div><div class=3D"gmail_extra">};</div><div class=3D"gmail_ex=
tra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_ext=
ra">This looks necessary but a bit problematic also. Apparently Modules wou=
ldn't change a thing as long</div><div class=3D"gmail_extra">as type me=
mbers are all considered exported.</div><div class=3D"gmail_extra"><br></di=
v><div class=3D"gmail_extra">Jo=C3=ABl Lamotte</div><div class=3D"gmail_ext=
ra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extr=
a"><br></div><div class=3D"gmail_extra"><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3=
Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1Q=
S1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com</a>.<br />
--001a11443c3a1d1fae05442f1999--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Wed, 21 Dec 2016 19:41:37 +0100
Raw View
--001a113d1ea8c8fd6205442f80d6
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
I suppose that if we want to use foo with B, one could include an operator
A() to B. In any case, the point in making a strong typedef is that you are
indeed making a new type. If it was completely compatible with the old one,
there would be little point, right?
In any case, I believe this case is what templates are for. They are there
to create functions that interact with object with the same interface, so
in this case one would want foo to be a templated function. Copy + Template
would be the equivalent of Inheritance + Interfaces. Maybe a way to clone
functions could be added in order to interface with old code, but I'm not
sure whether it should be in the scope of this proposal or be separated in
another one.
For member access, keep in mind that you are making a new class. The risk
is exactly the same when you create a new class and expose members which
should be private. In any case, this won't make you able to access A's
private members, only B's, which is different since it is another class
entirely. Why then you would want to create a new class which ignores
access specifiers is another problem, but one that exists independently of
this proposal.
On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail.c=
om>
wrote:
>
> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
> wrote:
>
>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
>> terminology.
>>
>
> Maybe use "clone-type" or something like that?
>
> Anyway yeah even for functions overloading there is always the same
> problem with any kind of strong typedef:
>
> class A {};
> class B : using/cloning A {};
>
> void foo(A& a);
>
> Here your proposal suggests that foo() cannot be used with B.
> But maybe we want that to be possible?
> Add a way to clone free functions too? How about allowing all operations
> from A to B?
>
> Also isn't there a risk of member access?
>
> class A {
> int hidden_value;
> public:
> A();
> };
>
> class B : using/cloning A
> {
> public:
>
> int cheat() { return hidden_value; }
> };
>
>
> This looks necessary but a bit problematic also. Apparently Modules
> wouldn't change a thing as long
> as type members are all considered exported.
>
> Jo=C3=ABl Lamotte
>
>
>
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZeb
> ChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0=
Cq1QS1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Dem=
ail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jGai3CtWNseLd=
A7QMNkw%40mail.gmail.com.
--001a113d1ea8c8fd6205442f80d6
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div>I suppose that if we want to use foo with B, one=
could include an operator A() to B. In any case, the point in making a str=
ong typedef is that you are indeed making a new type. If it was completely =
compatible with the old one, there would be little point, right?<br><br></d=
iv>In any case, I believe this case is what templates are for. They are the=
re to create functions that interact with object with the same interface, s=
o in this case one would want foo to be a templated function. Copy + Templa=
te would be the equivalent of Inheritance + Interfaces. Maybe a way to clon=
e functions could be added in order to interface with old code, but I'm=
not sure whether it should be in the scope of this proposal or be separate=
d in another one.<br><br></div>For member access, keep in mind that you are=
making a new class. The risk is exactly the same when you create a new cla=
ss and expose members which should be private. In any case, this won't =
make you able to access A's private members, only B's, which is dif=
ferent since it is another class entirely. Why then you would want to creat=
e a new class which ignores access specifiers is another problem, but one t=
hat exists independently of this proposal.<br></div><div class=3D"gmail_ext=
ra"><br><div class=3D"gmail_quote">On Wed, Dec 21, 2016 at 7:12 PM, Klaim -=
Jo=C3=ABl Lamotte <span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.co=
m" target=3D"_blank">mjklaim@gmail.com</a>></span> wrote:<br><blockquote=
class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><span class=
=3D""><br><div class=3D"gmail_quote">On 21 December 2016 at 13:41, Eugenio =
Bargiacchi <span dir=3D"ltr"><<a href=3D"mailto:svalorzen@gmail.com" tar=
get=3D"_blank">svalorzen@gmail.com</a>></span> wrote:<br><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;pa=
dding-left:1ex"><div>Jo<span class=3D"m_-1761669920559787611m_2157231802647=
884575m_-6092875754422023223gmail-_Tgc">=C3=ABl, about copy I feel the same=
way. I'll try to work out a nicer terminology.</span></div></blockquot=
e></div><br></span>Maybe use "clone-type" or something like that?=
</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Anywa=
y yeah even for functions overloading there is always the same problem with=
any kind of strong typedef:</div><div class=3D"gmail_extra"><br></div><div=
class=3D"gmail_extra">class A {};</div><div class=3D"gmail_extra">class B =
: using/cloning A {};</div><div class=3D"gmail_extra"><br></div><div class=
=3D"gmail_extra">void foo(A& a);</div><div class=3D"gmail_extra"><br></=
div><div class=3D"gmail_extra">Here your proposal suggests that foo() canno=
t be used with B.</div><div class=3D"gmail_extra">But maybe we want that to=
be possible?</div><div class=3D"gmail_extra">Add a way to clone free funct=
ions too? How about allowing all operations from A to B?</div><div class=3D=
"gmail_extra"><br></div><div class=3D"gmail_extra">Also isn't there a r=
isk of member access?</div><div class=3D"gmail_extra"><br></div><div class=
=3D"gmail_extra">class A {=C2=A0</div><div class=3D"gmail_extra">=C2=A0 =C2=
=A0 int hidden_value;=C2=A0</div><div class=3D"gmail_extra">=C2=A0 public:<=
/div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 A();</div><div class=
=3D"gmail_extra">};</div><div class=3D"gmail_extra"><br></div><div class=3D=
"gmail_extra">class B : using/cloning A</div><div class=3D"gmail_extra">{</=
div><div class=3D"gmail_extra">public:</div><div class=3D"gmail_extra"><br>=
</div><div class=3D"gmail_extra">=C2=A0 =C2=A0int cheat() { return hidden_v=
alue; }</div><div class=3D"gmail_extra">};</div><div class=3D"gmail_extra">=
<br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">T=
his looks necessary but a bit problematic also. Apparently Modules wouldn&#=
39;t change a thing as long</div><div class=3D"gmail_extra">as type members=
are all considered exported.</div><div class=3D"gmail_extra"><br></div><di=
v class=3D"gmail_extra">Jo=C3=ABl Lamotte</div><div class=3D"gmail_extra"><=
br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra"><b=
r></div><div class=3D"gmail_extra"><br></div></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3=
Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/st=
d-<wbr>proposals/<wbr>CAOU91OOQe0Cq1QS1bR1X0EsWDWZeb<wbr>ChkjoT3Dw7%2Bp9H6A=
Ag_tw%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jG=
ai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
>https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo=
2KXEWQHWQY6qB10oGabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com</a>.<br />
--001a113d1ea8c8fd6205442f80d6--
.
Author: "D. B." <db0451@gmail.com>
Date: Wed, 21 Dec 2016 18:57:56 +0000
Raw View
--001a1130cf06262ff405442fbbbc
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wed, Dec 21, 2016 at 6:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail.c=
om>
wrote:
>
> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
> wrote:
>
>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
>> terminology.
>>
>
> Maybe use "clone-type" or something like that?
>
> Anyway yeah even for functions overloading there is always the same
> problem with any kind of strong typedef:
>
> class A {};
> class B : using/cloning A {};
>
> void foo(A& a);
>
> Here your proposal suggests that foo() cannot be used with B.
> But maybe we want that to be possible?
>
Isn't like the entire point of strong typedefs that we don't want this kind
of substitutability to be possible with them?
> Add a way to clone free functions too? How about allowing all operations
> from A to B?
>
What does it mean to clone a function, and how does this relate to the
concept of strong typedefs?
> Also isn't there a risk of member access?
>
> class A {
> int hidden_value;
> public:
> A();
> };
>
> class B : using/cloning A
> {
> public:
>
> int cheat() { return hidden_value; }
> };
>
How would this be a problem? The point is to copy a class, so of course its
private members should be available.
At this point, I don't like the inheritance-like syntax much, but that's
separate, and conceptually, private members should be available.
This looks necessary but a bit problematic also. Apparently Modules
> wouldn't change a thing as long
> as type members are all considered exported.
>
Class members must be exported, and I don't see how that will or could
change with modules; it would be such a fundamental change to the language
that we might as well rename it at the same time.
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CACGiwhH-rn1AfPMxmcyC7T4DzBXtAYa5gqms7hr1QGX0VLE=
vvg%40mail.gmail.com.
--001a1130cf06262ff405442fbbbc
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><div class=3D"gmail_quo=
te">On Wed, Dec 21, 2016 at 6:12 PM, Klaim - Jo=C3=ABl Lamotte <span dir=3D=
"ltr"><<a href=3D"mailto:mjklaim@gmail.com" target=3D"_blank">mjklaim@gm=
ail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D=
"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D=
"ltr"><div class=3D"gmail_extra"><span class=3D""><br><div class=3D"gmail_q=
uote">On 21 December 2016 at 13:41, Eugenio Bargiacchi <span dir=3D"ltr">&l=
t;<a href=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.=
com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Jo<span cl=
ass=3D"m_6713852598127311164m_2157231802647884575m_-6092875754422023223gmai=
l-_Tgc">=C3=ABl, about copy I feel the same way. I'll try to work out a=
nicer terminology.</span></div></blockquote></div><br></span>Maybe use &qu=
ot;clone-type" or something like that?</div><div class=3D"gmail_extra"=
><br></div><div class=3D"gmail_extra">Anyway yeah even for functions overlo=
ading there is always the same problem with any kind of strong typedef:</di=
v><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class A {=
};</div><div class=3D"gmail_extra">class B : using/cloning A {};</div><div =
class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">void foo(A& =
a);</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">He=
re your proposal suggests that foo() cannot be used with B.</div><div class=
=3D"gmail_extra">But maybe we want that to be possible?</div></div></blockq=
uote><div><br></div><div>Isn't like the entire point of strong typedefs=
that we don't want this kind of substitutability to be possible with t=
hem?<br><br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=
=3D"ltr"><div class=3D"gmail_extra">Add a way to clone free functions too? =
How about allowing all operations from A to B?</div></div></blockquote><div=
><br></div><div>What does it mean to clone a function, and how does this re=
late to the concept of strong typedefs? <br></div><div><br>=C2=A0</div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"></di=
v><div class=3D"gmail_extra">Also isn't there a risk of member access?<=
/div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class =
A {=C2=A0</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 int hidden_value;=
=C2=A0</div><div class=3D"gmail_extra">=C2=A0 public:</div><div class=3D"gm=
ail_extra">=C2=A0 =C2=A0 =C2=A0 A();</div><div class=3D"gmail_extra">};</di=
v><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class B :=
using/cloning A</div><div class=3D"gmail_extra">{</div><div class=3D"gmail=
_extra">public:</div><div class=3D"gmail_extra"><br></div><div class=3D"gma=
il_extra">=C2=A0 =C2=A0int cheat() { return hidden_value; }</div><div>};<br=
></div></div></blockquote><div><br></div><div>How would this be a problem? =
The point is to copy a class, so of course its private members should be av=
ailable.<br><br></div><div>At this point, I don't like the inheritance-=
like syntax much, but that's separate, and conceptually, private member=
s should be available.<br></div><div>=C2=A0<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"></div><div class=
=3D"gmail_extra">This looks necessary but a bit problematic also. Apparentl=
y Modules wouldn't change a thing as long</div><div class=3D"gmail_extr=
a">as type members are all considered exported.</div></div></blockquote><di=
v><br></div><div>Class members must be exported, and I don't see how th=
at will or could change with modules; it would be such a fundamental=C2=A0 =
change to the language that we might as well rename it at the same time.<br=
><br></div></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhH-rn1AfPMxmcyC7T4DzBXtAYa5gqms=
7hr1QGX0VLEvvg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhH-rn1AfPMx=
mcyC7T4DzBXtAYa5gqms7hr1QGX0VLEvvg%40mail.gmail.com</a>.<br />
--001a1130cf06262ff405442fbbbc--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 21 Dec 2016 11:10:12 -0800 (PST)
Raw View
------=_Part_2072_1809287308.1482347412962
Content-Type: multipart/alternative;
boundary="----=_Part_2073_1236995966.1482347412962"
------=_Part_2073_1236995966.1482347412962
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wednesday, December 21, 2016 at 1:57:59 PM UTC-5, D. B. wrote:
>
> On Wed, Dec 21, 2016 at 6:12 PM, Klaim - Jo=C3=ABl Lamotte <mjk...@gmail.=
com=20
> <javascript:>> wrote:
>
>>
>> On 21 December 2016 at 13:41, Eugenio Bargiacchi <sval...@gmail.com=20
>> <javascript:>> wrote:
>>
>>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer=
=20
>>> terminology.
>>>
>>
>> Maybe use "clone-type" or something like that?
>>
>> Anyway yeah even for functions overloading there is always the same=20
>> problem with any kind of strong typedef:
>>
>> class A {};
>> class B : using/cloning A {};
>>
>> void foo(A& a);
>>
>> Here your proposal suggests that foo() cannot be used with B.
>> But maybe we want that to be possible?
>>
>
> Isn't like the entire point of strong typedefs that we don't want this=20
> kind of substitutability to be possible with them?
>
Sometimes it is. And sometimes it isn't. Sometimes a non-member function is=
=20
just a regular function that takes `A`. And sometimes, it is genuinely part=
=20
of `A`'s interface. Operators being one of the most important such=20
functions, but there are others.
This is why strong typedef proposals are so complex. To pick either answer=
=20
for all functions inhibits the utility of the feature in some way.
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/915ad9c0-9d50-4759-aa70-f143dc77ce8a%40isocpp.or=
g.
------=_Part_2073_1236995966.1482347412962
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Wednesday, December 21, 2016 at 1:57:59 PM UTC-5, D. B.=
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><=
div class=3D"gmail_quote">On Wed, Dec 21, 2016 at 6:12 PM, Klaim - Jo=C3=AB=
l Lamotte <span dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank" g=
df-obfuscated-mailto=3D"75lrywsADAAJ" rel=3D"nofollow" onmousedown=3D"this.=
href=3D'javascript:';return true;" onclick=3D"this.href=3D'java=
script:';return true;">mjk...@gmail.com</a>></span> wrote:<br><block=
quote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div dir=3D"ltr"><div><span><br><div class=3D"gmai=
l_quote">On 21 December 2016 at 13:41, Eugenio Bargiacchi <span dir=3D"ltr"=
><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"75l=
rywsADAAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D'javascript:'=
;;return true;" onclick=3D"this.href=3D'javascript:';return true;">=
sval...@gmail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote=
" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><=
div>Jo<span>=C3=ABl, about copy I feel the same way. I'll try to work o=
ut a nicer terminology.</span></div></blockquote></div><br></span>Maybe use=
"clone-type" or something like that?</div><div><br></div><div>An=
yway yeah even for functions overloading there is always the same problem w=
ith any kind of strong typedef:</div><div><br></div><div>class A {};</div><=
div>class B : using/cloning A {};</div><div><br></div><div>void foo(A& =
a);</div><div><br></div><div>Here your proposal suggests that foo() cannot =
be used with B.</div><div>But maybe we want that to be possible?</div></div=
></blockquote><div><br></div><div>Isn't like the entire point of strong=
typedefs that we don't want this kind of substitutability to be possib=
le with them?<br></div></div></div></div></blockquote><div><br>Sometimes it=
is. And sometimes it isn't. Sometimes a non-member function is just a =
regular function that takes `A`. And sometimes, it is genuinely part of `A`=
's interface. Operators being one of the most important such functions,=
but there are others.<br><br>This is why strong typedef proposals are so c=
omplex. To pick either answer for all functions inhibits the utility of the=
feature in some way.<br></div><blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
>
</blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/915ad9c0-9d50-4759-aa70-f143dc77ce8a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/915ad9c0-9d50-4759-aa70-f143dc77ce8a=
%40isocpp.org</a>.<br />
------=_Part_2073_1236995966.1482347412962--
------=_Part_2072_1809287308.1482347412962--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Wed, 21 Dec 2016 20:20:22 +0100
Raw View
--047d7b5d86955ef86a0544300bb0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On 21 December 2016 at 19:41, Eugenio Bargiacchi <svalorzen@gmail.com>
wrote:
> I suppose that if we want to use foo with B, one could include an operato=
r
> A() to B.
>
Not necessarily:
class A
{
std::mutex my_mutex; // not copyable or moveable, not part of the
interface
public:
A();
};
class B : using/cloning A
{};
I expect this to work but not that B could be convertible to A without a
static cast.
> In any case, the point in making a strong typedef is that you are indeed
> making a new type. If it was completely compatible with the old one, ther=
e
> would be little point, right?
>
>
I agree but in the same time, most types you need to clone have free
functions as part of their interfaces.
This is a classic problem with strong typedefs.
> In any case, I believe this case is what templates are for. They are ther=
e
> to create functions that interact with object with the same interface, so
> in this case one would want foo to be a templated function.
>
It would be nice but you are talking about a function you might not have
control over with.
It can be solved with a cast though.
> Copy + Template would be the equivalent of Inheritance + Interfaces. Mayb=
e
> a way to clone functions could be added in order to interface with old
> code, but I'm not sure whether it should be in the scope of this proposal
> or be separated in another one.
>
>
Maybe not, maybe begin with what you have to get initial feedback.
I watched recently Stroustrup explain that in the end he is not for strong
typedefs feaures anymore, because just create a type and go with it.
So I believe that any attempt to put the feature back in discussion will
have to pass a higher barrier of interest, even if Stroustrup is "only"
one vote.
> For member access, keep in mind that you are making a new class. The risk
> is exactly the same when you create a new class and expose members which
> should be private. In any case, this won't make you able to access A's
> private members, only B's, which is different since it is another class
> entirely. Why then you would want to create a new class which ignores
> access specifiers is another problem, but one that exists independently o=
f
> this proposal.
>
>
Ah yes, I understand.
> On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail=
..com>
> wrote:
>
>>
>> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
>> wrote:
>>
>>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
>>> terminology.
>>>
>>
>> Maybe use "clone-type" or something like that?
>>
>> Anyway yeah even for functions overloading there is always the same
>> problem with any kind of strong typedef:
>>
>> class A {};
>> class B : using/cloning A {};
>>
>> void foo(A& a);
>>
>> Here your proposal suggests that foo() cannot be used with B.
>> But maybe we want that to be possible?
>> Add a way to clone free functions too? How about allowing all operations
>> from A to B?
>>
>> Also isn't there a risk of member access?
>>
>> class A {
>> int hidden_value;
>> public:
>> A();
>> };
>>
>> class B : using/cloning A
>> {
>> public:
>>
>> int cheat() { return hidden_value; }
>> };
>>
>>
>> This looks necessary but a bit problematic also. Apparently Modules
>> wouldn't change a thing as long
>> as type members are all considered exported.
>>
>> Jo=C3=ABl Lamotte
>>
>>
>>
>>
>> --
>> 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/is
>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe
>> bChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe=
0Cq1QS1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3De=
mail&utm_source=3Dfooter>
>> .
>>
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jGai
> 3CtWNseLdA7QMNkw%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
vo2KXEWQHWQY6qB10oGabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=3D=
email&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%2BdLr979ZkPDLh7junqx=
_DETQ%40mail.gmail.com.
--047d7b5d86955ef86a0544300bb0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><div class=3D"gmail_quo=
te">On 21 December 2016 at 19:41, Eugenio Bargiacchi <span dir=3D"ltr"><=
<a href=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.co=
m</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margi=
n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">=
<div><div>I suppose that if we want to use foo with B, one could include an=
operator A() to B.</div></div></div></blockquote><div><br></div><div>Not n=
ecessarily:</div><div><br></div><div>class A</div><div>{</div><div>=C2=A0 =
=C2=A0std::mutex my_mutex; // not copyable or moveable, not part of the int=
erface</div><div>public:</div><div><br></div><div>=C2=A0 =C2=A0 A();=C2=A0<=
/div><div>};</div><div><br></div><div>class B : using/cloning A</div><div>{=
};</div><div><br></div><div>I expect this to work but not that B could be c=
onvertible to A without a static cast.</div><div>=C2=A0</div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div><div> In any case, the point in maki=
ng a strong typedef is that you are indeed making a new type. If it was com=
pletely compatible with the old one, there would be little point, right?<br=
><br></div></div></div></blockquote><div><br></div><div>I agree but in the =
same time, most types you need to clone have free functions as part of thei=
r interfaces.</div><div>This is a classic problem with strong typedefs.</di=
v><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 =
..8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><di=
v></div>In any case, I believe this case is what templates are for. They ar=
e there to create functions that interact with object with the same interfa=
ce, so in this case one would want foo to be a templated function.</div></d=
iv></blockquote><div><br></div><div>It would be nice but you are talking ab=
out a function you might not have control over with.</div><div>It can be so=
lved with a cast though.</div><div>=C2=A0</div><blockquote class=3D"gmail_q=
uote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div dir=3D"ltr"><div> Copy + Template would be the equivalent of Inheri=
tance + Interfaces. Maybe a way to clone functions could be added in order =
to interface with old code, but I'm not sure whether it should be in th=
e scope of this proposal or be separated in another one.<br><br></div></div=
></blockquote><div><br></div><div>Maybe not, maybe begin with what you have=
to get initial feedback.</div><div>I watched recently Stroustrup explain t=
hat in the end he is not for strong typedefs feaures anymore, because just =
create a type and go with it.</div><div>So I believe that any attempt to pu=
t the feature back in discussion will have to pass a higher barrier of inte=
rest, even if Stroustrup is "only"</div><div>one vote.</div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></div>For =
member access, keep in mind that you are making a new class. The risk is ex=
actly the same when you create a new class and expose members which should =
be private. In any case, this won't make you able to access A's pri=
vate members, only B's, which is different since it is another class en=
tirely. Why then you would want to create a new class which ignores access =
specifiers is another problem, but one that exists independently of this pr=
oposal.<br></div><div class=3D"gmail_extra"><br></div></blockquote><div><br=
></div><div>Ah yes, I understand.</div><div><br></div><div>=C2=A0</div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div class=3D"gmail_extra"><div class=3D"gmail_q=
uote"><div><div class=3D"h5">On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=
=ABl Lamotte <span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.com" tar=
get=3D"_blank">mjklaim@gmail.com</a>></span> wrote:<br></div></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div><div class=3D"h5"><div dir=3D"ltr"><div clas=
s=3D"gmail_extra"><span><br><div class=3D"gmail_quote">On 21 December 2016 =
at 13:41, Eugenio Bargiacchi <span dir=3D"ltr"><<a href=3D"mailto:svalor=
zen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a>></span> wrote:<=
br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left=
:1px #ccc solid;padding-left:1ex"><div>Jo<span class=3D"m_22530487683072378=
27m_-1761669920559787611m_2157231802647884575m_-6092875754422023223gmail-_T=
gc">=C3=ABl, about copy I feel the same way. I'll try to work out a nic=
er terminology.</span></div></blockquote></div><br></span>Maybe use "c=
lone-type" or something like that?</div><div class=3D"gmail_extra"><br=
></div><div class=3D"gmail_extra">Anyway yeah even for functions overloadin=
g there is always the same problem with any kind of strong typedef:</div><d=
iv class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class A {};</=
div><div class=3D"gmail_extra">class B : using/cloning A {};</div><div clas=
s=3D"gmail_extra"><br></div><div class=3D"gmail_extra">void foo(A& a);<=
/div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Here y=
our proposal suggests that foo() cannot be used with B.</div><div class=3D"=
gmail_extra">But maybe we want that to be possible?</div><div class=3D"gmai=
l_extra">Add a way to clone free functions too? How about allowing all oper=
ations from A to B?</div><div class=3D"gmail_extra"><br></div><div class=3D=
"gmail_extra">Also isn't there a risk of member access?</div><div class=
=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class A {=C2=A0</div>=
<div class=3D"gmail_extra">=C2=A0 =C2=A0 int hidden_value;=C2=A0</div><div =
class=3D"gmail_extra">=C2=A0 public:</div><div class=3D"gmail_extra">=C2=A0=
=C2=A0 =C2=A0 A();</div><div class=3D"gmail_extra">};</div><div class=3D"g=
mail_extra"><br></div><div class=3D"gmail_extra">class B : using/cloning A<=
/div><div class=3D"gmail_extra">{</div><div class=3D"gmail_extra">public:</=
div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">=C2=A0 =
=C2=A0int cheat() { return hidden_value; }</div><div class=3D"gmail_extra">=
};</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra"><br=
></div><div class=3D"gmail_extra">This looks necessary but a bit problemati=
c also. Apparently Modules wouldn't change a thing as long</div><div cl=
ass=3D"gmail_extra">as type members are all considered exported.</div><div =
class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Jo=C3=ABl Lamott=
e</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra"><br>=
</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra"><br><=
/div></div></div></div><span class=3D""><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3=
Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe<wbr>bChkjoT3Dw7%2Bp9H6AAg_tw=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jG=
ai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/=
std-<wbr>proposals/CAHfn%3D%<wbr>2Bvo2KXEWQHWQY6qB10oGabvZ9jGai<wbr>3CtWNse=
LdA7QMNkw%40mail.gmail.<wbr>com</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%2BdLr979Z=
kPDLh7junqx_DETQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_v=
CxNryKEdgA4W%2BdLr979ZkPDLh7junqx_DETQ%40mail.gmail.com</a>.<br />
--047d7b5d86955ef86a0544300bb0--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Wed, 21 Dec 2016 20:27:48 +0100
Raw View
--047d7b5d8695f6471205443025c6
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On 21 December 2016 at 19:57, D. B. <db0451@gmail.com> wrote:
>
>
> On Wed, Dec 21, 2016 at 6:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail=
..com>
> wrote:
>
>>
>> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
>> wrote:
>>
>>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nicer
>>> terminology.
>>>
>>
>> Maybe use "clone-type" or something like that?
>>
>> Anyway yeah even for functions overloading there is always the same
>> problem with any kind of strong typedef:
>>
>> class A {};
>> class B : using/cloning A {};
>>
>> void foo(A& a);
>>
>> Here your proposal suggests that foo() cannot be used with B.
>> But maybe we want that to be possible?
>>
>
> Isn't like the entire point of strong typedefs that we don't want this
> kind of substitutability to be possible with them?
>
>
As Nicol Bolas said.
>
>
>> Add a way to clone free functions too? How about allowing all operations
>> from A to B?
>>
>
> What does it mean to clone a function, and how does this relate to the
> concept of strong typedefs?
>
>
Cloning a function:
A foo(A&);
The cloned function would be equivalent to
B foo(B&b ) { B result =3D some_cast foo( some_cast<A&>(b) ); return result=
; }
But the replaced types would need to be clone relatives.
Also it wouldn't be very interesting if the syntax wouldn't allow to do
that with "all" the functions
relaetd to the original type.
But it's all speculation and ideas, I didn't think much more than that.
>
>
>> Also isn't there a risk of member access?
>>
>> class A {
>> int hidden_value;
>> public:
>> A();
>> };
>>
>> class B : using/cloning A
>> {
>> public:
>>
>> int cheat() { return hidden_value; }
>> };
>>
>
> How would this be a problem? The point is to copy a class, so of course
> its private members should be available.
>
> At this point, I don't like the inheritance-like syntax much, but that's
> separate, and conceptually, private members should be available.
>
>
Indeed.
>
> This looks necessary but a bit problematic also. Apparently Modules
>> wouldn't change a thing as long
>> as type members are all considered exported.
>>
>
> Class members must be exported, and I don't see how that will or could
> change with modules;
>
It was not proposed at first and my understanding is that the main author
of Modules believe it is possible to not export the private members.
(if my memory from discussions is correct)
> it would be such a fundamental change to the language that we might as
> well rename it at the same time.
>
>
It wouldn't change more in the language than when you use code that come
with a header stripped from details and a binary to link with.
But yeah it would change things from the source usage pov.
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CACGiwhH-rn1AfPMxmcyC7T4DzBXtAYa5gqms7h
> r1QGX0VLEvvg%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhH-rn=
1AfPMxmcyC7T4DzBXtAYa5gqms7hr1QGX0VLEvvg%40mail.gmail.com?utm_medium=3Demai=
l&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOU91OP1pbd2qUVrpSdYKsCbgP7%3D7qe5EVo-6OP-snOR4=
O9O3Q%40mail.gmail.com.
--047d7b5d8695f6471205443025c6
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><div class=3D"gmail_quo=
te">On 21 December 2016 at 19:57, D. B. <span dir=3D"ltr"><<a href=3D"ma=
ilto:db0451@gmail.com" target=3D"_blank">db0451@gmail.com</a>></span> wr=
ote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border=
-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><br><div class=3D"g=
mail_extra"><br><div class=3D"gmail_quote"><span class=3D"">On Wed, Dec 21,=
2016 at 6:12 PM, Klaim - Jo=C3=ABl Lamotte <span dir=3D"ltr"><<a href=
=3D"mailto:mjklaim@gmail.com" target=3D"_blank">mjklaim@gmail.com</a>></=
span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_extra"><span><br><div class=3D"gmail_quote">On 21 December 2016 a=
t 13:41, Eugenio Bargiacchi <span dir=3D"ltr"><<a href=3D"mailto:svalorz=
en@gmail.com" target=3D"_blank">svalorzen@gmail.com</a>></span> wrote:<b=
r><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div>Jo<span class=3D"m_-87647905526253224=
9m_6713852598127311164m_2157231802647884575m_-6092875754422023223gmail-_Tgc=
">=C3=ABl, about copy I feel the same way. I'll try to work out a nicer=
terminology.</span></div></blockquote></div><br></span>Maybe use "clo=
ne-type" or something like that?</div><div class=3D"gmail_extra"><br><=
/div><div class=3D"gmail_extra">Anyway yeah even for functions overloading =
there is always the same problem with any kind of strong typedef:</div><div=
class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">class A {};</di=
v><div class=3D"gmail_extra">class B : using/cloning A {};</div><div class=
=3D"gmail_extra"><br></div><div class=3D"gmail_extra">void foo(A& a);</=
div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Here yo=
ur proposal suggests that foo() cannot be used with B.</div><div class=3D"g=
mail_extra">But maybe we want that to be possible?</div></div></blockquote>=
<div><br></div></span><div>Isn't like the entire point of strong typede=
fs that we don't want this kind of substitutability to be possible with=
them?<br><br></div></div></div></div></blockquote><div><br></div><div>As N=
icol Bolas said.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div =
dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div></di=
v><span class=3D""><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=
=3D"ltr"><div class=3D"gmail_extra">Add a way to clone free functions too? =
How about allowing all operations from A to B?</div></div></blockquote><div=
><br></div></span><div>What does it mean to clone a function, and how does =
this relate to the concept of strong typedefs? <br></div><span class=3D""><=
div><br></div></span></div></div></div></blockquote><div><br></div><div>Clo=
ning a function:</div><div><br></div><div>A foo(A&);</div><div><br></di=
v><div>The cloned function would be equivalent to</div><div><br></div><div>=
B foo(B&b ) { B result =3D some_cast foo( some_cast<A&>(b) );=
return result; }</div><div><br></div><div>But the replaced types would nee=
d to be clone relatives.</div><div><br></div><div>Also it wouldn't be v=
ery interesting if the syntax wouldn't allow to do that with "all&=
quot; the functions</div><div>relaetd to the original type.</div><div><br><=
/div><div>But it's all speculation and ideas, I didn't think much m=
ore than that.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=
=3D""><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 =
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div=
class=3D"gmail_extra"></div><div class=3D"gmail_extra">Also isn't ther=
e a risk of member access?</div><div class=3D"gmail_extra"><br></div><div c=
lass=3D"gmail_extra">class A {=C2=A0</div><div class=3D"gmail_extra">=C2=A0=
=C2=A0 int hidden_value;=C2=A0</div><div class=3D"gmail_extra">=C2=A0 publ=
ic:</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 A();</div><div cla=
ss=3D"gmail_extra">};</div><div class=3D"gmail_extra"><br></div><div class=
=3D"gmail_extra">class B : using/cloning A</div><div class=3D"gmail_extra">=
{</div><div class=3D"gmail_extra">public:</div><div class=3D"gmail_extra"><=
br></div><div class=3D"gmail_extra">=C2=A0 =C2=A0int cheat() { return hidde=
n_value; }</div><div>};<br></div></div></blockquote><div><br></div></span><=
div>How would this be a problem? The point is to copy a class, so of course=
its private members should be available.<br><br></div><div>At this point, =
I don't like the inheritance-like syntax much, but that's separate,=
and conceptually, private members should be available.<br></div><span clas=
s=3D""><div>=C2=A0<br></div></span></div></div></div></blockquote><div><br>=
</div><div>Indeed.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" =
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><di=
v dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span c=
lass=3D""><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><d=
iv class=3D"gmail_extra"></div><div class=3D"gmail_extra">This looks necess=
ary but a bit problematic also. Apparently Modules wouldn't change a th=
ing as long</div><div class=3D"gmail_extra">as type members are all conside=
red exported.</div></div></blockquote><div><br></div></span><div>Class memb=
ers must be exported, and I don't see how that will or could change wit=
h modules;</div></div></div></div></blockquote><div><br></div><div>It was n=
ot proposed at first and my understanding is that the main author of Module=
s believe it is possible to not export the private members.</div><div>(if m=
y memory from discussions is correct)</div><div>=C2=A0</div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;pa=
dding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"g=
mail_quote"><div> it would be such a fundamental=C2=A0 change to the langua=
ge that we might as well rename it at the same time.<br><br></div></div></d=
iv></div></blockquote><div><br></div><div>It wouldn't change more in th=
e language than when you use code that come with a header stripped from det=
ails and a binary to link with.</div><div>But yeah it would change things f=
rom the source usage pov.</div><div>=C2=A0</div><blockquote class=3D"gmail_=
quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">=
<div></div></div></div></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CACGiwhH-rn1AfPMxmcyC7T4DzBXtAYa5gqms=
7hr1QGX0VLEvvg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-=
<wbr>proposals/CACGiwhH-<wbr>rn1AfPMxmcyC7T4DzBXtAYa5gqms7h<wbr>r1QGX0VLEvv=
g%40mail.gmail.com</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OP1pbd2qUVrpSdYKsCbgP7%3D7qe5EV=
o-6OP-snOR4O9O3Q%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OP1pbd2qU=
VrpSdYKsCbgP7%3D7qe5EVo-6OP-snOR4O9O3Q%40mail.gmail.com</a>.<br />
--047d7b5d8695f6471205443025c6--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Wed, 21 Dec 2016 20:28:11 +0100
Raw View
--001a114fa2344923ae05443027df
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
>
> I agree but in the same time, most types you need to clone have free
> functions as part of their interfaces.
> This is a classic problem with strong typedefs.
>
I agree, I have though a while about this while writing this proposal. I
thought about giving the possibility of "cloning" a function (as in,
creating an equivalent version line by line with just all instances of the
copied type replaced by the new type) within the scope of the copied class.
But then I realized that if that was allowed, at that point it might as
well be allowed for all classes, for all functions. And so it would become
a feature on its own, or at least a very big scope increase. Thus I removed
it from the proposal.
If you feel that such a feature cannot be reasonably excluded from a
complete proposal about strong typing, I'll try to think about a way to
extend the syntax for functions, or even better find something which looks
equally good for both classes and functions.
My first guess was that maybe trying to keep the proposal as limited in
scope as possible would be best, so that it would be easier what could go
wrong. Even a small step towards strong typing would be better than
nothing, I guess. Even if some classes can be harder to copy/clone if they
are mostly defined by their free-functions ecosystem, still there's many
for which this is not true.
But again, if you feel it would be best to think about this and try to add
it, I'll definitely try to.
On Wed, Dec 21, 2016 at 8:20 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail.c=
om>
wrote:
>
>
> On 21 December 2016 at 19:41, Eugenio Bargiacchi <svalorzen@gmail.com>
> wrote:
>
>> I suppose that if we want to use foo with B, one could include an
>> operator A() to B.
>>
>
> Not necessarily:
>
> class A
> {
> std::mutex my_mutex; // not copyable or moveable, not part of the
> interface
> public:
>
> A();
> };
>
> class B : using/cloning A
> {};
>
> I expect this to work but not that B could be convertible to A without a
> static cast.
>
>
>> In any case, the point in making a strong typedef is that you are indeed
>> making a new type. If it was completely compatible with the old one, the=
re
>> would be little point, right?
>>
>>
> I agree but in the same time, most types you need to clone have free
> functions as part of their interfaces.
> This is a classic problem with strong typedefs.
>
>
>> In any case, I believe this case is what templates are for. They are
>> there to create functions that interact with object with the same
>> interface, so in this case one would want foo to be a templated function=
..
>>
>
> It would be nice but you are talking about a function you might not have
> control over with.
> It can be solved with a cast though.
>
>
>> Copy + Template would be the equivalent of Inheritance + Interfaces.
>> Maybe a way to clone functions could be added in order to interface with
>> old code, but I'm not sure whether it should be in the scope of this
>> proposal or be separated in another one.
>>
>>
> Maybe not, maybe begin with what you have to get initial feedback.
> I watched recently Stroustrup explain that in the end he is not for stron=
g
> typedefs feaures anymore, because just create a type and go with it.
> So I believe that any attempt to put the feature back in discussion will
> have to pass a higher barrier of interest, even if Stroustrup is "only"
> one vote.
>
>
>> For member access, keep in mind that you are making a new class. The ris=
k
>> is exactly the same when you create a new class and expose members which
>> should be private. In any case, this won't make you able to access A's
>> private members, only B's, which is different since it is another class
>> entirely. Why then you would want to create a new class which ignores
>> access specifiers is another problem, but one that exists independently =
of
>> this proposal.
>>
>>
> Ah yes, I understand.
>
>
>
>> On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmai=
l.com>
>> wrote:
>>
>>>
>>> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
>>> wrote:
>>>
>>>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nice=
r
>>>> terminology.
>>>>
>>>
>>> Maybe use "clone-type" or something like that?
>>>
>>> Anyway yeah even for functions overloading there is always the same
>>> problem with any kind of strong typedef:
>>>
>>> class A {};
>>> class B : using/cloning A {};
>>>
>>> void foo(A& a);
>>>
>>> Here your proposal suggests that foo() cannot be used with B.
>>> But maybe we want that to be possible?
>>> Add a way to clone free functions too? How about allowing all operation=
s
>>> from A to B?
>>>
>>> Also isn't there a risk of member access?
>>>
>>> class A {
>>> int hidden_value;
>>> public:
>>> A();
>>> };
>>>
>>> class B : using/cloning A
>>> {
>>> public:
>>>
>>> int cheat() { return hidden_value; }
>>> };
>>>
>>>
>>> This looks necessary but a bit problematic also. Apparently Modules
>>> wouldn't change a thing as long
>>> as type members are all considered exported.
>>>
>>> Jo=C3=ABl Lamotte
>>>
>>>
>>>
>>>
>>> --
>>> 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/is
>>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>>> To unsubscribe from this group and all its topics, send an email to
>>> std-proposals+unsubscribe@isocpp.org.
>>> To post to this group, send email to std-proposals@isocpp.org.
>>> To view this discussion on the web visit https://groups.google.com/a/is
>>> ocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe
>>> bChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com
>>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQ=
e0Cq1QS1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3D=
email&utm_source=3Dfooter>
>>> .
>>>
>>
>> --
>> You received this message because you are subscribed to the Google Group=
s
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n
>> email to std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10o
>> GabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2=
Bvo2KXEWQHWQY6qB10oGabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
>> .
>>
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%
> 2BdLr979ZkPDLh7junqx_DETQ%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWWC=
Lw_vCxNryKEdgA4W%2BdLr979ZkPDLh7junqx_DETQ%40mail.gmail.com?utm_medium=3Dem=
ail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BvYTB4zJT7zsQ8chPRJCj7m%3DP3yv1v_tMREZ=
jfr%3DeSFpA%40mail.gmail.com.
--001a114fa2344923ae05443027df
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div><div><div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex"><div>I agree but in the same time, most types you need to clone=
have free functions as part of their interfaces.</div><div>This is a class=
ic problem with strong typedefs.</div></blockquote><br>I agree, I have thou=
gh a while about this while writing this=20
proposal. I thought about giving the possibility of "cloning" a f=
unction
(as in, creating an equivalent version line by line with just all=20
instances of the copied type replaced by the new type) within the scope=20
of the copied class.<br><br></div>But then I realized that if that was=20
allowed, at that point it might as well be allowed for all classes, for all=
functions. And=20
so it would become a feature on its own, or at least a very big scope incre=
ase. Thus I removed it from the=20
proposal.<br><br></div>If you feel that such a feature cannot be reasonably=
excluded from a complete proposal about strong typing, I'll try to thi=
nk about a way to extend the syntax for functions, or even better find some=
thing which looks equally good for both classes and functions.<br><br></div=
>My first guess was that maybe trying to keep the proposal as limited in sc=
ope as possible would be best, so that it would be easier what could go wro=
ng. Even a small step towards strong typing would be better than nothing, I=
guess. Even if some classes can be harder to copy/clone if they are mostly=
defined by their free-functions ecosystem, still there's many for whic=
h this is not true.<br><br></div>But again, if you feel it would be best to=
think about this and try to add it, I'll definitely try to.<br></div><=
div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Wed, Dec 21, 20=
16 at 8:20 PM, Klaim - Jo=C3=ABl Lamotte <span dir=3D"ltr"><<a href=3D"m=
ailto:mjklaim@gmail.com" target=3D"_blank">mjklaim@gmail.com</a>></span>=
wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><br><div class=
=3D"gmail_extra"><br><div class=3D"gmail_quote"><span class=3D"">On 21 Dece=
mber 2016 at 19:41, Eugenio Bargiacchi <span dir=3D"ltr"><<a href=3D"mai=
lto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a>></spa=
n> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><div>I su=
ppose that if we want to use foo with B, one could include an operator A() =
to B.</div></div></div></blockquote><div><br></div></span><div>Not necessar=
ily:</div><div><br></div><div>class A</div><div>{</div><div>=C2=A0 =C2=A0st=
d::mutex my_mutex; // not copyable or moveable, not part of the interface</=
div><span class=3D""><div>public:</div><div><br></div><div>=C2=A0 =C2=A0 A(=
);=C2=A0</div><div>};</div><div><br></div><div>class B : using/cloning A</d=
iv></span><div>{};</div><div><br></div><div>I expect this to work but not t=
hat B could be convertible to A without a static cast.</div><span class=3D"=
"><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 =
..8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><di=
v> In any case, the point in making a strong typedef is that you are indeed=
making a new type. If it was completely compatible with the old one, there=
would be little point, right?<br><br></div></div></div></blockquote><div><=
br></div></span><div>I agree but in the same time, most types you need to c=
lone have free functions as part of their interfaces.</div><div>This is a c=
lassic problem with strong typedefs.</div><span class=3D""><div>=C2=A0</div=
><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1=
px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><div></div>In any cas=
e, I believe this case is what templates are for. They are there to create =
functions that interact with object with the same interface, so in this cas=
e one would want foo to be a templated function.</div></div></blockquote><d=
iv><br></div></span><div>It would be nice but you are talking about a funct=
ion you might not have control over with.</div><div>It can be solved with a=
cast though.</div><span class=3D""><div>=C2=A0</div><blockquote class=3D"g=
mail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-l=
eft:1ex"><div dir=3D"ltr"><div> Copy + Template would be the equivalent of =
Inheritance + Interfaces. Maybe a way to clone functions could be added in =
order to interface with old code, but I'm not sure whether it should be=
in the scope of this proposal or be separated in another one.<br><br></div=
></div></blockquote><div><br></div></span><div>Maybe not, maybe begin with =
what you have to get initial feedback.</div><div>I watched recently Stroust=
rup explain that in the end he is not for strong typedefs feaures anymore, =
because just create a type and go with it.</div><div>So I believe that any =
attempt to put the feature back in discussion will have to pass a higher ba=
rrier of interest, even if Stroustrup is "only"</div><div>one vot=
e.</div><span class=3D""><div>=C2=A0</div><blockquote class=3D"gmail_quote"=
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv dir=3D"ltr"><div></div>For member access, keep in mind that you are maki=
ng a new class. The risk is exactly the same when you create a new class an=
d expose members which should be private. In any case, this won't make =
you able to access A's private members, only B's, which is differen=
t since it is another class entirely. Why then you would want to create a n=
ew class which ignores access specifiers is another problem, but one that e=
xists independently of this proposal.<br></div><div class=3D"gmail_extra"><=
br></div></blockquote><div><br></div></span><div>Ah yes, I understand.</div=
><div><br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D=
"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div c=
lass=3D"h5"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div><div=
class=3D"m_-3377085949348013313h5">On Wed, Dec 21, 2016 at 7:12 PM, Klaim =
- Jo=C3=ABl Lamotte <span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.c=
om" target=3D"_blank">mjklaim@gmail.com</a>></span> wrote:<br></div></di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div><div class=3D"m_-3377085949348013313h=
5"><div dir=3D"ltr"><div class=3D"gmail_extra"><span><br><div class=3D"gmai=
l_quote">On 21 December 2016 at 13:41, Eugenio Bargiacchi <span dir=3D"ltr"=
><<a href=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gma=
il.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Jo<span=
class=3D"m_-3377085949348013313m_2253048768307237827m_-1761669920559787611=
m_2157231802647884575m_-6092875754422023223gmail-_Tgc">=C3=ABl, about copy =
I feel the same way. I'll try to work out a nicer terminology.</span></=
div></blockquote></div><br></span>Maybe use "clone-type" or somet=
hing like that?</div><div class=3D"gmail_extra"><br></div><div class=3D"gma=
il_extra">Anyway yeah even for functions overloading there is always the sa=
me problem with any kind of strong typedef:</div><div class=3D"gmail_extra"=
><br></div><div class=3D"gmail_extra">class A {};</div><div class=3D"gmail_=
extra">class B : using/cloning A {};</div><div class=3D"gmail_extra"><br></=
div><div class=3D"gmail_extra">void foo(A& a);</div><div class=3D"gmail=
_extra"><br></div><div class=3D"gmail_extra">Here your proposal suggests th=
at foo() cannot be used with B.</div><div class=3D"gmail_extra">But maybe w=
e want that to be possible?</div><div class=3D"gmail_extra">Add a way to cl=
one free functions too? How about allowing all operations from A to B?</div=
><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Also isn&#=
39;t there a risk of member access?</div><div class=3D"gmail_extra"><br></d=
iv><div class=3D"gmail_extra">class A {=C2=A0</div><div class=3D"gmail_extr=
a">=C2=A0 =C2=A0 int hidden_value;=C2=A0</div><div class=3D"gmail_extra">=
=C2=A0 public:</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 A();</d=
iv><div class=3D"gmail_extra">};</div><div class=3D"gmail_extra"><br></div>=
<div class=3D"gmail_extra">class B : using/cloning A</div><div class=3D"gma=
il_extra">{</div><div class=3D"gmail_extra">public:</div><div class=3D"gmai=
l_extra"><br></div><div class=3D"gmail_extra">=C2=A0 =C2=A0int cheat() { re=
turn hidden_value; }</div><div class=3D"gmail_extra">};</div><div class=3D"=
gmail_extra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"g=
mail_extra">This looks necessary but a bit problematic also. Apparently Mod=
ules wouldn't change a thing as long</div><div class=3D"gmail_extra">as=
type members are all considered exported.</div><div class=3D"gmail_extra">=
<br></div><div class=3D"gmail_extra">Jo=C3=ABl Lamotte</div><div class=3D"g=
mail_extra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"gm=
ail_extra"><br></div><div class=3D"gmail_extra"><br></div></div></div></div=
><span><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3=
Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe<wbr>bChkjoT3Dw7%2Bp9H6AAg_tw=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div></div></div><span>
<p></p>
-- <br><span class=3D"">
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br></span>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<span class=3D""><br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jG=
ai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/=
std-proposals<wbr>/CAHfn%3D%2Bvo2KXEWQHWQY6qB10o<wbr>GabvZ9jGai3CtWNseLdA7Q=
MNkw%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%2BdLr979Z=
kPDLh7junqx_DETQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/st=
d-<wbr>proposals/CAOU91ONWWCLw_<wbr>vCxNryKEdgA4W%<wbr>2BdLr979ZkPDLh7junqx=
_DETQ%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvYTB4zJT7zsQ8chPRJCj7m%3DP=
3yv1v_tMREZjfr%3DeSFpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%=
2BvYTB4zJT7zsQ8chPRJCj7m%3DP3yv1v_tMREZjfr%3DeSFpA%40mail.gmail.com</a>.<br=
/>
--001a114fa2344923ae05443027df--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Wed, 21 Dec 2016 20:31:34 +0100
Raw View
--001a11443c3a6a2de705443033dc
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On 21 December 2016 at 20:28, Eugenio Bargiacchi <svalorzen@gmail.com>
wrote:
> I agree but in the same time, most types you need to clone have free
>> functions as part of their interfaces.
>> This is a classic problem with strong typedefs.
>>
>
> I agree, I have though a while about this while writing this proposal. I
> thought about giving the possibility of "cloning" a function (as in,
> creating an equivalent version line by line with just all instances of th=
e
> copied type replaced by the new type) within the scope of the copied clas=
s.
>
> But then I realized that if that was allowed, at that point it might as
> well be allowed for all classes, for all functions. And so it would becom=
e
> a feature on its own, or at least a very big scope increase. Thus I remov=
ed
> it from the proposal.
>
> If you feel that such a feature cannot be reasonably excluded from a
> complete proposal about strong typing, I'll try to think about a way to
> extend the syntax for functions, or even better find something which look=
s
> equally good for both classes and functions.
>
> My first guess was that maybe trying to keep the proposal as limited in
> scope as possible would be best, so that it would be easier what could go
> wrong. Even a small step towards strong typing would be better than
> nothing, I guess. Even if some classes can be harder to copy/clone if the=
y
> are mostly defined by their free-functions ecosystem, still there's many
> for which this is not true.
>
> But again, if you feel it would be best to think about this and try to ad=
d
> it, I'll definitely try to.
>
I agree,
I think it would be ok to just mention the possibility in the proposal and
write a separate proposal.
I don't have practical experience with such a feature so maybe it's not
even important (I think it can be, but maybe the effort with already
standardized code would not be that verbose to write).
>
> On Wed, Dec 21, 2016 at 8:20 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gmail=
..com>
> wrote:
>
>>
>>
>> On 21 December 2016 at 19:41, Eugenio Bargiacchi <svalorzen@gmail.com>
>> wrote:
>>
>>> I suppose that if we want to use foo with B, one could include an
>>> operator A() to B.
>>>
>>
>> Not necessarily:
>>
>> class A
>> {
>> std::mutex my_mutex; // not copyable or moveable, not part of the
>> interface
>> public:
>>
>> A();
>> };
>>
>> class B : using/cloning A
>> {};
>>
>> I expect this to work but not that B could be convertible to A without a
>> static cast.
>>
>>
>>> In any case, the point in making a strong typedef is that you are indee=
d
>>> making a new type. If it was completely compatible with the old one, th=
ere
>>> would be little point, right?
>>>
>>>
>> I agree but in the same time, most types you need to clone have free
>> functions as part of their interfaces.
>> This is a classic problem with strong typedefs.
>>
>>
>>> In any case, I believe this case is what templates are for. They are
>>> there to create functions that interact with object with the same
>>> interface, so in this case one would want foo to be a templated functio=
n.
>>>
>>
>> It would be nice but you are talking about a function you might not have
>> control over with.
>> It can be solved with a cast though.
>>
>>
>>> Copy + Template would be the equivalent of Inheritance + Interfaces.
>>> Maybe a way to clone functions could be added in order to interface wit=
h
>>> old code, but I'm not sure whether it should be in the scope of this
>>> proposal or be separated in another one.
>>>
>>>
>> Maybe not, maybe begin with what you have to get initial feedback.
>> I watched recently Stroustrup explain that in the end he is not for
>> strong typedefs feaures anymore, because just create a type and go with =
it.
>> So I believe that any attempt to put the feature back in discussion will
>> have to pass a higher barrier of interest, even if Stroustrup is "only"
>> one vote.
>>
>>
>>> For member access, keep in mind that you are making a new class. The
>>> risk is exactly the same when you create a new class and expose members
>>> which should be private. In any case, this won't make you able to acces=
s
>>> A's private members, only B's, which is different since it is another c=
lass
>>> entirely. Why then you would want to create a new class which ignores
>>> access specifiers is another problem, but one that exists independently=
of
>>> this proposal.
>>>
>>>
>> Ah yes, I understand.
>>
>>
>>
>>> On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=ABl Lamotte <mjklaim@gma=
il.com
>>> > wrote:
>>>
>>>>
>>>> On 21 December 2016 at 13:41, Eugenio Bargiacchi <svalorzen@gmail.com>
>>>> wrote:
>>>>
>>>>> Jo=C3=ABl, about copy I feel the same way. I'll try to work out a nic=
er
>>>>> terminology.
>>>>>
>>>>
>>>> Maybe use "clone-type" or something like that?
>>>>
>>>> Anyway yeah even for functions overloading there is always the same
>>>> problem with any kind of strong typedef:
>>>>
>>>> class A {};
>>>> class B : using/cloning A {};
>>>>
>>>> void foo(A& a);
>>>>
>>>> Here your proposal suggests that foo() cannot be used with B.
>>>> But maybe we want that to be possible?
>>>> Add a way to clone free functions too? How about allowing all
>>>> operations from A to B?
>>>>
>>>> Also isn't there a risk of member access?
>>>>
>>>> class A {
>>>> int hidden_value;
>>>> public:
>>>> A();
>>>> };
>>>>
>>>> class B : using/cloning A
>>>> {
>>>> public:
>>>>
>>>> int cheat() { return hidden_value; }
>>>> };
>>>>
>>>>
>>>> This looks necessary but a bit problematic also. Apparently Modules
>>>> wouldn't change a thing as long
>>>> as type members are all considered exported.
>>>>
>>>> Jo=C3=ABl Lamotte
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> 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/is
>>>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>>>> To unsubscribe from this group and all its topics, send an email to
>>>> std-proposals+unsubscribe@isocpp.org.
>>>> To post to this group, send email to std-proposals@isocpp.org.
>>>> To view this discussion on the web visit https://groups.google.com/a/i=
s
>>>> ocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe
>>>> bChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com
>>>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OO=
Qe0Cq1QS1bR1X0EsWDWZebChkjoT3Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
>>>> .
>>>>
>>>
>>> --
>>> 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-proposals+unsubscribe@isocpp.org.
>>> To post to this group, send email to std-proposals@isocpp.org.
>>> To view this discussion on the web visit https://groups.google.com/a/is
>>> ocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10o
>>> GabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com
>>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%=
2Bvo2KXEWQHWQY6qB10oGabvZ9jGai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
>>> .
>>>
>>
>> --
>> 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/is
>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%2
>> BdLr979ZkPDLh7junqx_DETQ%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWW=
CLw_vCxNryKEdgA4W%2BdLr979ZkPDLh7junqx_DETQ%40mail.gmail.com?utm_medium=3De=
mail&utm_source=3Dfooter>
>> .
>>
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvYTB4zJT7zsQ8chPRJCj7m%
> 3DP3yv1v_tMREZjfr%3DeSFpA%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
vYTB4zJT7zsQ8chPRJCj7m%3DP3yv1v_tMREZjfr%3DeSFpA%40mail.gmail.com?utm_mediu=
m=3Demail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOU91OPSB-BRLxM7CV26ZFysor2L3C8DALiFXLhgE7zFYqd=
v%3DA%40mail.gmail.com.
--001a11443c3a6a2de705443033dc
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><div class=3D"gmail_quo=
te">On 21 December 2016 at 20:28, Eugenio Bargiacchi <span dir=3D"ltr"><=
<a href=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.co=
m</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margi=
n:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex=
"><div dir=3D"ltr"><div><div><div><div><span class=3D"gmail-"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px soli=
d rgb(204,204,204);padding-left:1ex"><div>I agree but in the same time, mos=
t types you need to clone have free functions as part of their interfaces.<=
/div><div>This is a classic problem with strong typedefs.</div></blockquote=
><br></span>I agree, I have though a while about this while writing this=20
proposal. I thought about giving the possibility of "cloning" a f=
unction
(as in, creating an equivalent version line by line with just all=20
instances of the copied type replaced by the new type) within the scope=20
of the copied class.<br><br></div>But then I realized that if that was=20
allowed, at that point it might as well be allowed for all classes, for all=
functions. And=20
so it would become a feature on its own, or at least a very big scope incre=
ase. Thus I removed it from the=20
proposal.<br><br></div>If you feel that such a feature cannot be reasonably=
excluded from a complete proposal about strong typing, I'll try to thi=
nk about a way to extend the syntax for functions, or even better find some=
thing which looks equally good for both classes and functions.<br></div></d=
iv></div></blockquote><div><br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex"><div dir=3D"ltr"><div><div><br></div>My first guess was that ma=
ybe trying to keep the proposal as limited in scope as possible would be be=
st, so that it would be easier what could go wrong. Even a small step towar=
ds strong typing would be better than nothing, I guess. Even if some classe=
s can be harder to copy/clone if they are mostly defined by their free-func=
tions ecosystem, still there's many for which this is not true.<br><br>=
</div>But again, if you feel it would be best to think about this and try t=
o add it, I'll definitely try to.<br></div></blockquote><div><br></div>=
<div>I agree,=C2=A0</div><div>I think it would be ok to just mention the po=
ssibility in the proposal and write a separate proposal.</div><div>I don=
9;t have practical experience with such a feature so maybe it's not eve=
n important (I think it can be, but maybe the effort with already</div><div=
>standardized code would not be that verbose to write).</div><div>=C2=A0=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"=
></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote"><div><div =
class=3D"gmail-h5">On Wed, Dec 21, 2016 at 8:20 PM, Klaim - Jo=C3=ABl Lamot=
te <span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.com" target=3D"_bl=
ank">mjklaim@gmail.com</a>></span> wrote:<br></div></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div><div class=3D"gmail-h5"><div dir=3D=
"ltr"><br><div class=3D"gmail_extra"><br><div class=3D"gmail_quote"><span>O=
n 21 December 2016 at 19:41, Eugenio Bargiacchi <span dir=3D"ltr"><<a hr=
ef=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorzen@gmail.com</a>=
></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><di=
v dir=3D"ltr"><div><div>I suppose that if we want to use foo with B, one co=
uld include an operator A() to B.</div></div></div></blockquote><div><br></=
div></span><div>Not necessarily:</div><div><br></div><div>class A</div><div=
>{</div><div>=C2=A0 =C2=A0std::mutex my_mutex; // not copyable or moveable,=
not part of the interface</div><span><div>public:</div><div><br></div><div=
>=C2=A0 =C2=A0 A();=C2=A0</div><div>};</div><div><br></div><div>class B : u=
sing/cloning A</div></span><div>{};</div><div><br></div><div>I expect this =
to work but not that B could be convertible to A without a static cast.</di=
v><span><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">=
<div dir=3D"ltr"><div><div> In any case, the point in making a strong typed=
ef is that you are indeed making a new type. If it was completely compatibl=
e with the old one, there would be little point, right?<br><br></div></div>=
</div></blockquote><div><br></div></span><div>I agree but in the same time,=
most types you need to clone have free functions as part of their interfac=
es.</div><div>This is a classic problem with strong typedefs.</div><span><d=
iv>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0p=
x 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div><div></div>In any case, I believe this case is what templates=
are for. They are there to create functions that interact with object with=
the same interface, so in this case one would want foo to be a templated f=
unction.</div></div></blockquote><div><br></div></span><div>It would be nic=
e but you are talking about a function you might not have control over with=
..</div><div>It can be solved with a cast though.</div><span><div>=C2=A0</di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div> =
Copy + Template would be the equivalent of Inheritance + Interfaces. Maybe =
a way to clone functions could be added in order to interface with old code=
, but I'm not sure whether it should be in the scope of this proposal o=
r be separated in another one.<br><br></div></div></blockquote><div><br></d=
iv></span><div>Maybe not, maybe begin with what you have to get initial fee=
dback.</div><div>I watched recently Stroustrup explain that in the end he i=
s not for strong typedefs feaures anymore, because just create a type and g=
o with it.</div><div>So I believe that any attempt to put the feature back =
in discussion will have to pass a higher barrier of interest, even if Strou=
strup is "only"</div><div>one vote.</div><span><div>=C2=A0</div><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div></di=
v>For member access, keep in mind that you are making a new class. The risk=
is exactly the same when you create a new class and expose members which s=
hould be private. In any case, this won't make you able to access A'=
;s private members, only B's, which is different since it is another cl=
ass entirely. Why then you would want to create a new class which ignores a=
ccess specifiers is another problem, but one that exists independently of t=
his proposal.<br></div><div class=3D"gmail_extra"><br></div></blockquote><d=
iv><br></div></span><div>Ah yes, I understand.</div><div><br></div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class=
=3D"gmail-m_-8375142242869947228h5"><div class=3D"gmail_extra"><div class=
=3D"gmail_quote"><div><div class=3D"gmail-m_-8375142242869947228m_-33770859=
49348013313h5">On Wed, Dec 21, 2016 at 7:12 PM, Klaim - Jo=C3=ABl Lamotte <=
span dir=3D"ltr"><<a href=3D"mailto:mjklaim@gmail.com" target=3D"_blank"=
>mjklaim@gmail.com</a>></span> wrote:<br></div></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><div><div class=3D"gmail-m_-83751422428699=
47228m_-3377085949348013313h5"><div dir=3D"ltr"><div class=3D"gmail_extra">=
<span><br><div class=3D"gmail_quote">On 21 December 2016 at 13:41, Eugenio =
Bargiacchi <span dir=3D"ltr"><<a href=3D"mailto:svalorzen@gmail.com" tar=
get=3D"_blank">svalorzen@gmail.com</a>></span> wrote:<br><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div>Jo<span class=3D"gmail-m_-837514224=
2869947228m_-3377085949348013313m_2253048768307237827m_-1761669920559787611=
m_2157231802647884575m_-6092875754422023223gmail-_Tgc">=C3=ABl, about copy =
I feel the same way. I'll try to work out a nicer terminology.</span></=
div></blockquote></div><br></span>Maybe use "clone-type" or somet=
hing like that?</div><div class=3D"gmail_extra"><br></div><div class=3D"gma=
il_extra">Anyway yeah even for functions overloading there is always the sa=
me problem with any kind of strong typedef:</div><div class=3D"gmail_extra"=
><br></div><div class=3D"gmail_extra">class A {};</div><div class=3D"gmail_=
extra">class B : using/cloning A {};</div><div class=3D"gmail_extra"><br></=
div><div class=3D"gmail_extra">void foo(A& a);</div><div class=3D"gmail=
_extra"><br></div><div class=3D"gmail_extra">Here your proposal suggests th=
at foo() cannot be used with B.</div><div class=3D"gmail_extra">But maybe w=
e want that to be possible?</div><div class=3D"gmail_extra">Add a way to cl=
one free functions too? How about allowing all operations from A to B?</div=
><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Also isn&#=
39;t there a risk of member access?</div><div class=3D"gmail_extra"><br></d=
iv><div class=3D"gmail_extra">class A {=C2=A0</div><div class=3D"gmail_extr=
a">=C2=A0 =C2=A0 int hidden_value;=C2=A0</div><div class=3D"gmail_extra">=
=C2=A0 public:</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 A();</d=
iv><div class=3D"gmail_extra">};</div><div class=3D"gmail_extra"><br></div>=
<div class=3D"gmail_extra">class B : using/cloning A</div><div class=3D"gma=
il_extra">{</div><div class=3D"gmail_extra">public:</div><div class=3D"gmai=
l_extra"><br></div><div class=3D"gmail_extra">=C2=A0 =C2=A0int cheat() { re=
turn hidden_value; }</div><div class=3D"gmail_extra">};</div><div class=3D"=
gmail_extra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"g=
mail_extra">This looks necessary but a bit problematic also. Apparently Mod=
ules wouldn't change a thing as long</div><div class=3D"gmail_extra">as=
type members are all considered exported.</div><div class=3D"gmail_extra">=
<br></div><div class=3D"gmail_extra">Jo=C3=ABl Lamotte</div><div class=3D"g=
mail_extra"><br></div><div class=3D"gmail_extra"><br></div><div class=3D"gm=
ail_extra"><br></div><div class=3D"gmail_extra"><br></div></div></div></div=
><span><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OOQe0Cq1QS1bR1X0EsWDWZebChkjoT3=
Dw7%2Bp9H6AAg_tw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CAOU91OOQe0Cq1QS1bR1X0EsWDWZe<wbr>bChkjoT3Dw7%2Bp9H6AAg_tw=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div></div></div><span>
<p></p>
-- <br><span>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br></span>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<span><br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bvo2KXEWQHWQY6qB10oGabvZ9jG=
ai3CtWNseLdA7QMNkw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/=
std-proposals<wbr>/CAHfn%3D%2Bvo2KXEWQHWQY6qB10o<wbr>GabvZ9jGai3CtWNseLdA7Q=
MNkw%40m<wbr>ail.gmail.com</a>.<br>
</blockquote></div><br></div></div><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></div></div=
>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91ONWWCLw_vCxNryKEdgA4W%2BdLr979Z=
kPDLh7junqx_DETQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CAOU91ONWWCLw_vCxNryKEdgA4W%2<wbr>BdLr979ZkPDLh7junqx_DETQ=
%40mai<wbr>l.gmail.com</a>.<br>
</blockquote></div><br></div><span class=3D"gmail-">
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvYTB4zJT7zsQ8chPRJCj7m%3DP=
3yv1v_tMREZjfr%3DeSFpA%40mail.gmail.com?utm_medium=3Demail&utm_source=
=3Dfooter" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/=
msgid/std-<wbr>proposals/CAHfn%3D%<wbr>2BvYTB4zJT7zsQ8chPRJCj7m%<wbr>3DP3yv=
1v_tMREZjfr%3DeSFpA%<wbr>40mail.gmail.com</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOU91OPSB-BRLxM7CV26ZFysor2L3C8DALiF=
XLhgE7zFYqdv%3DA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OPSB-BRLx=
M7CV26ZFysor2L3C8DALiFXLhgE7zFYqdv%3DA%40mail.gmail.com</a>.<br />
--001a11443c3a6a2de705443033dc--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sat, 31 Dec 2016 12:14:50 +0100
Raw View
This is a multi-part message in MIME format.
--------------7DED0E8F175F195436D6A87B
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 19/12/2016 =C3=A0 12:04, svalorzen@gmail.com a =C3=A9crit :
> This is a stub proposal on strong typedefs, i.e. types that work in=20
> the exact same way, but allow separate overloading. Other papers and=20
> proposals exist, but I've tried a different approach that tries to=20
> mimic a more inheritance-like syntax which might be more intuitive.=20
> The full text can be found online at=20
> https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text=20
> below. Thanks in advance for your comments.
Hi,
your proposal has the merit to propose a different approach. IIUC, you=20
approach consists in introducing/duplicating all members (type, data,=20
functions, constructors/destructors) from the underlying class, but no=20
the friends.
p0109r0 introduce only conversions to/from the underlying type.
IIUC, every occurrence of the base type in the definition of the base=20
type is replaced by the new type. This is one of the options described=20
in Opaque proposal (see The return type issue). Why the other=20
alternatives have less sens?
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing=20
> functionality
> while wrapping it in a new type, without the burden of inheritance and=20
> to allow
> function overloads on syntactically identical but semantically=20
> different types
> (also known as *strong typedef*).
>
The word duplicating and wrapping don't match. The proposed approach=20
doesn't wraps the underlying type, except maybe for builtin types.
> The approach taken should be simple to implement and be applicable to=20
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but=20
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending=20
> on context
> have currently no simple way to indicate the semantic differences.=20
> Since a
> `typedef` does not allow multiple overloads on new typedef types -=20
> since they
> are still the "old" type - they have to resort to imperfect=20
> techniques, such
> as copying, wrapping or inheriting the needed type. Examples:=20
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather=20
> than
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste=20
> alternative.
> This can result in very deep hierarchies of types which should=20
> really not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but=20
> partially
> extend it with context-specific methods. Examples: search for=20
> "`std::vector`
> inheritance" yields many results of users trying to maintain the=20
> original
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
I believe the proposal needs to add some concrete examples as use cases
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type.=20
> However, this
> leaves no space to implement overloads that are context-specific. Nor=20
> a type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a=20
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even=20
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to=20
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in=20
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original=20
> interface in
> order to be able to duplicate it correctly. Template methods, rvalue=20
> references,
> possibly undocumented methods which are required in order to allow the=20
> class to
> behave in the same way as before. This heightens the bar significantly=20
> for many
> users, since they may not know correctly how to duplicate an interface=20
> and how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
If the base class change, the strong types depending on it could need=20
maintenance also, isn't it?
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs=20
> discovered
> in one class must be fixed in the other class too. All new features=20
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and=20
> implementation
> of a given class just one time, and used multiple times to produce=20
> separate
> classes.
>
> This approach is unfortunately not applicable to existing code, and is=20
> very hard
> to extend if one wants to copy a class but add additional=20
> functionality to it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are=20
> unfortunately
> not applicable to previously existing code. For new code, they would=20
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible:=20
> variations would
> need to be made through specialization, which itself requires copying=20
> existing
> code.
>
In addition to these basic techniques, there are other library solution,=20
as e.g. using CRTP that might merit to be mentioned.
See [TBoost.Opaque] for a possible implementation.
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language=20
> multiple times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf=
),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf=
),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs=20
> are named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private`=20
> are used
> in order to create a specific relation with the original type and how=20
> is the
> new type allowed to be cast back to the original type or be used in=20
> its place
> during overloads.
>
Please add=20
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf to=20
this list.
> This document shares many of the the same principles, for example=20
> (quoting from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships=20
> such as
> > base classes underlying derived classes and integer types=20
> underlying enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed.=20
> We also do
> > not require that any enum type, reference type, array type,=20
> function type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple=20
> approach, where
> a new language feature is introduced with the same meaning and=20
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more=20
> simple to
> understand (as it simply matches already the already understood=20
> mechanics of
> creating a new, unique type from nothing), and no new rules for type=20
> conversion
> and selection on overloads have to be created.
What is wrong for you with p0109r0 approach?
What we could have with your approach that we cannot have with p0109r0?
What we could have with p0109r0 that we cannot have with your approach?
IIUC, p0109r0 opaque types don't introduce any operations by default=20
other than conversions and your proposal introduce all members but no=20
friends
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
is this almost equivalent to p0109r0
using Copy : private Base {
using Base::foo; // if this was allowed in p0109r0
};
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class=20
> is needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would=20
> inherit
> from the same classes its base class inherits from. All constructors=20
> would work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of=20
> Base, to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion=20
> operators can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility=20
> were needed,
> one would only need to implement them once, since copying the produced=20
> type
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
I find that conversions to/from the underlying type must be covered by=20
the proposal. If we change the Base type we don't want to be forced to=20
redefine the conversion operator.
Maybe we need some kind of default conversion implementation
operator Base() *=3D default*;
or
*explicit* operator Base() *=3D default*;
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
Agree reinterpret_cast should be allowed.
>
> In general the usual rules of `reinterpret_cast` apply to the copied=20
> classes
> with respect to their general classes, exactly as if the copied class=20
> had been
> implemented by hand.
>
> <snip>
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating=20
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template=20
> parameters than
> the base class.
Why do you introduce this restriction?
> <snip>
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because=20
> each copy
> would depend on the originals, rather than on the copied classes. A=20
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A; // **
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal=20
> `using`
> alias directive. `using class` is only valid when the left hand side=20
> has been
> defined as a copy of the right hand side.
In ** above C has not yet defined as a copy
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
I believe this interdependent case introduce a lot of complexity. We=20
would need a good use case to introduce it on the standard.
> ### Substituting Existing Functionality (Optional) ###
>
I believe that this cannot be optional as in a lot of cases we need to=20
modify/restrict the base type interface.
> Ideally one may want to use most of an implementation for another=20
> class, but
> vary a certain number of methods. In this case, if `Copy` contains a=20
> member
> function that already exists in `Base`, then that implementation is=20
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of=20
> "interface", where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed=20
> also alter
> behavior and/or variable types of non-modified member and non-member=20
> functions,
> since the new behavior could be either erroneous or ambiguous.
Could you give a concrete example of this kind of problems?
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types.=20
> Using the
> extension that allows the modification of the copied types, this could=20
> allow for
> creation of numeric types where some operations are disabled as needed.
Note the missing friend below
> ```cpp
> struct Id : using int {
> *friend *Id operator+(Id, Id) =3D delete;
> *friend *Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
While this is inline with your approach, this merits some explanations=20
as the operators are no members. Shouldn't the operators of UDT classes=20
meritt to be inherited as well?
> // Defining new operators with the old type can allow interoperativity
> *friend *Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
I believed that there where no implicit conversions on your proposals.=20
How (*this) is converted to an int?
What would be the result type of x below?
Id id(1);
auto x =3D +id;
I suspect that it would be Id.
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden=20
> as the
> generated copy is `final` (although it is allowed to keep copying the=20
> newly
> created class).
Why this restriction is needed or desirable.
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine=20
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
Example of where this can be useful welcome.
How other type traits behave for the copied class (see p0109r0)?
In summary, I believe that
Vicente
[p0109r0]=20
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf
[TBoost.Opaque]=20
https://htmlpreview.github.io/?https://github.com/viboes/opaque/blob/master=
/libs/opaque/doc/html/index.html
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/9574d1c1-b3ff-b9ae-ceee-908a2b983278%40wanadoo.f=
r.
--------------7DED0E8F175F195436D6A87B
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 19/12/2016 =C3=A0 12:04,
<a class=3D"moz-txt-link-abbreviated" href=3D"mailto:svalorzen@gmail.=
com">svalorzen@gmail.com</a> a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr">This is a stub proposal on strong typedefs, i.e.
types that work in the exact same way, but allow separate
overloading. Other papers and proposals exist, but I've tried a
different approach that tries to mimic a more inheritance-like
syntax which might be more intuitive. The full text can be found
online at <a moz-do-not-send=3D"true"
href=3D"https://github.com/Svalorzen/CppCopyProposal">https://git=
hub.com/Svalorzen/CppCopyProposal.<br>
<br>
</a>I'm copying the text below. Thanks in advance for your
comments.<br>
</div>
</blockquote>
Hi,<br>
<br>
your proposal has the merit to propose a different approach. IIUC,
you approach consists in introducing/duplicating all members (type,
data, functions, constructors/destructors) from the underlying
class, but no the friends.<br>
p0109r0 introduce only conversions to/from the underlying type.<br>
<br>
IIUC, every occurrence of the base type in the definition of the
base type is replaced by the new type. This is one of the options
described in Opaque proposal (see The return type issue). Why the
other alternatives have less sens?<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><br>
<span style=3D"font-family: courier new,monospace;">Duplication
and Extension of Existing Classes<br>
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br=
>
<br>
Introduction<br>
------------<br>
<br>
This document describes a possible approach to duplicate
existing functionality<br>
while wrapping it in a new type, without the burden of
inheritance and to allow<br>
function overloads on syntactically identical but semantically
different types<br>
(also known as *strong typedef*).<br>
<br>
</span></div>
</blockquote>
The word duplicating and wrapping don't match. The proposed approach
doesn't wraps the underlying type, except maybe for builtin types.<br>
=C2=A0<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
The
approach taken should be simple to implement and be applicable
to existing<br>
code.<br>
<br>
Optional sections are to be read as additional ideas that
could be further<br>
developed or completely ignored. They are mostly food for
thought, but included<br>
for completeness.<br>
<br>
Reasons<br>
-------<br>
<br>
- Scientific libraries where a type has different behaviors
depending on context<br>
=C2=A0 have currently no simple way to indicate the semantic
differences. Since a<br>
=C2=A0 `typedef` does not allow multiple overloads on new typedef
types - since they<br>
=C2=A0 are still the "old" type - they have to resort to imperfec=
t
techniques, such<br>
=C2=A0 as copying, wrapping or inheriting the needed type.
Examples: coordinates in a<br>
=C2=A0 plane (rectangular, polar), vectors of double
(probabilities, values).<br>
- Easier maintainability of code which is known to be the
same, rather than<br>
=C2=A0 being copy-pasted.<br>
- Avoiding misuse of inheritance in order to provide a
copy-paste alternative.<br>
=C2=A0 This can result in very deep hierarchies of types which
should really not have<br>
=C2=A0 anything to do with each other.<br>
- Enabling users to use an existing and presumably correct
type but partially<br>
=C2=A0 extend it with context-specific methods. Examples: search
for "`std::vector`<br>
=C2=A0 inheritance" yields many results of users trying to mainta=
in
the original<br>
=C2=A0 interface and functionality but add one or two methods.<br=
>
<br>
The functionality should have the following requirements:<br>
<br>
- Can be applied to existing code.<br>
- Should limit dependencies between new and old type as much
as possible.<br>
- Should allow for partial extensions of the old code.<br>
<br>
</span></div>
</blockquote>
I believe the proposal needs to add some concrete examples as use
cases<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
Alternatives<br>
------------<br>
<br>
### Typedef / Using Directive ###<br>
<br>
Using a type alias creates an alternative name for a single
type. However, this<br>
leaves no space to implement overloads that are
context-specific. Nor a type can<br>
be extended in a simple way while keeping the old interface
intact.<br>
<br>
### Inheritance ###<br>
<br>
Inheritance requires redefinition of all constructors, and
creates a stricter<br>
dependency between two classes than what is proposed here.
Classes may be<br>
converted to a common ancestor even though that is undesired
or even dangerous<br>
in case of implicit conversions.<br>
<br>
Inheritance may also be unwanted in order to avoid risks
linked to polymorphism<br>
and freeing data structures where the base class does not have
a virtual<br>
destructor.<br>
<br>
### Encapsulation with Manual Exposure of Needed Methods ###<br>
<br>
This method obviously requires a great deal of code to be
rewritten in order to<br>
wrap every single method that the old class was exposing.<br>
<br>
In addition one needs to have intimate knowledge of the
original interface in<br>
order to be able to duplicate it correctly. Template methods,
rvalue references,<br>
possibly undocumented methods which are required in order to
allow the class to<br>
behave in the same way as before. This heightens the bar
significantly for many<br>
users, since they may not know correctly how to duplicate an
interface and how<br>
to forward parameters to the old interface correctly.<br>
<br>
The new code also must be maintained in case the old interface
changes.<br>
</span></div>
</blockquote>
If the base class change, the strong types depending on it could
need maintenance also, isn't it?<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
### Copying the Base Class ###<br>
<br>
This can be useful, but requires all code to be duplicated,
and thus<br>
significantly increases the burden of maintaining the code.
All bugs discovered<br>
in one class must be fixed in the other class too. All new
features applied to<br>
one class must be applied to the other too.<br>
<br>
### Macro-expansion ###<br>
<br>
Macro expansions can be used in order to encode the interface
and implementation<br>
of a given class just one time, and used multiple times to
produce separate<br>
classes.<br>
<br>
This approach is unfortunately not applicable to existing
code, and is very hard<br>
to extend if one wants to copy a class but add additional
functionality to it.<br>
<br>
### Templates ###<br>
<br>
Templates produce for each instantiation a separate type. They
are unfortunately<br>
not applicable to previously existing code. For new code, they
would require the<br>
creation of "fake" template parameters that would need to vary
in order to<br>
produce separate types.<br>
<br>
In addition, class extension through templates is not
possible: variations would<br>
need to be made through specialization, which itself requires
copying existing<br>
code.<br>
<br>
</span></div>
</blockquote>
In addition to these basic techniques, there are other library
solution, as e.g. using CRTP that might merit to be mentioned.<br>
See [TBoost.Opaque] for a possible implementation.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
Previous
Work<br>
-------------<br>
<br>
Strong typedefs have already been proposed for the C++
language multiple times<br>
([N1706](<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org=
/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf">http://www.open-std.org/jtc1/sc=
22/wg21/docs/papers/2004/n1706.pdf</a>),<br>
[N1891](<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/=
jtc1/sc22/wg21/docs/papers/2005/n1891.pdf">http://www.open-std.org/jtc1/sc2=
2/wg21/docs/papers/2005/n1891.pdf</a>),<br>
[N3515](<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/=
jtc1/sc22/wg21/docs/papers/2013/n3515.pdf">http://www.open-std.org/jtc1/sc2=
2/wg21/docs/papers/2013/n3515.pdf</a>),<br>
[N3741](<a class=3D"moz-txt-link-freetext" href=3D"https://isocpp=
..org/files/papers/n3741.pdf">https://isocpp.org/files/papers/n3741.pdf</a>)=
). These
typedefs are named<br>
*opaque typedefs*, and these papers try to explore and define
exactly the<br>
behavior that such typedefs should and would have when used to
create new<br>
types. In particular, the keywords `public`, `protected` and
`private` are used<br>
in order to create a specific relation with the original type
and how is the<br>
new type allowed to be cast back to the original type or be
used in its place<br>
during overloads.<br>
<br>
</span></div>
</blockquote>
Please add
<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2015/p0109r0.pdf">http://www.open-std.org/jtc1/sc22/=
wg21/docs/papers/2015/p0109r0.pdf</a>
to this list.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
This
document shares many of the the same principles, for example
(quoting from<br>
N3741):<br>
<br>
> - Consistent with restrictions imposed on analogous
relationships such as<br>
>=C2=A0=C2=A0 base classes underlying derived classes and inte=
ger
types underlying enums,<br>
>=C2=A0=C2=A0 an underlying type should be (1) complete and (2=
) not
cv-quali=EF=AC=81ed. We also do<br>
>=C2=A0=C2=A0 not require that any enum type, reference type, =
array
type, function type, or<br>
>=C2=A0=C2=A0 pointer-to-member type be allowed as an underlyi=
ng
type.<br>
<br>
However, this document tries to propose a possibly more simple
approach, where<br>
a new language feature is introduced with the same meaning and
functionality as<br>
if the user autonomously implemented a new class him/herself,
matching the<br>
original type completely. Thus, it should result for the user
more simple to<br>
understand (as it simply matches already the already
understood mechanics of<br>
creating a new, unique type from nothing), and no new rules
for type conversion<br>
and selection on overloads have to be created.<br>
</span></div>
</blockquote>
What is wrong for you with p0109r0 approach?<br>
What we could have with your approach that we cannot have with
p0109r0?<br>
What we could have with p0109r0 that we cannot have with your
approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce any operations by default
other than conversions and your proposal introduce all members but
no friends<br>
<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
Syntax<br>
------<br>
<br>
### Simple Case ###<br>
<br>
Syntax could look something like this:<br>
<br>
```cpp<br>
class Base {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout=
<< "foo " << x
<< "\n"; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
};<br>
<br>
struct Copy : using Base {};<br>
<br>
</span></div>
</blockquote>
is this almost equivalent to p0109r0<br>
<br>
=C2=A0=C2=A0=C2=A0 using Copy : private Base {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 using Base::foo; // if this was a=
llowed in p0109r0<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
/*
Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout=
<< "foo " << x
<< "\n"; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
};<br>
<br>
*/<br>
```<br>
<br>
One cannot copy a class and inherit at the same time. If such
a class is needed<br>
one would need to create it by hand with the desided
functionality and<br>
inheriting from the desired classes, as it would be done
normally.<br>
<br>
All method implementations would be the same. The copied class
would inherit<br>
from the same classes its base class inherits from. All
constructors would work<br>
in the same way.<br>
<br>
### Adding New Functionality ###<br>
<br>
Ideally one could specify additional methods, separate from
that of Base, to add<br>
upon the existing functionality.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<br>
};<br>
<br>
struct Derived : public Base {};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>
};<br>
<br>
struct CopyDerived : using Derived {};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>
};<br>
<br>
struct CopyDerived : public Base {};<br>
<br>
*/<br>
```<br>
<br>
Only new methods need to be implemented for that class.<br>
<br>
#### Interfacing with the Original Class ####<br>
<br>
In order to interface with the original class, simple
conversion operators can<br>
be added by the user explicitly at-will, in order to obtain
the desired<br>
interface. Note that if more types with this kind of
compatibility were needed,<br>
one would only need to implement them once, since copying the
produced type<br>
would copy the new, more compatible interface with it.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>
};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>
};<br>
```<br>
<br>
</span></div>
</blockquote>
I find that conversions to/from the underlying type must be covered
by the proposal. If we change the Base type we don't want to be
forced to redefine the conversion operator.<br>
Maybe we need some kind of default conversion implementation<br>
<br>
<span style=3D"font-family: courier new,monospace;">=C2=A0=C2=A0=C2=A0 =
operator
Base() <b>=3D default</b>;<br>
<br>
or <br>
</span><br>
<span style=3D"font-family: courier new,monospace;">=C2=A0=C2=A0=C2=A0 =
<b>explicit</b>
operator Base() <b>=3D default</b>;<br>
</span>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
`reinterpret_cast`
may also be used to convert back to the original class,<br>
limited by the tool's already existing rules.<br>
</span></div>
</blockquote>
Agree reinterpret_cast should be allowed.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
In general the usual rules of `reinterpret_cast` apply to the
copied classes<br>
with respect to their general classes, exactly as if the
copied class had been<br>
implemented by hand.<br>
<br>
<snip><br>
<br>
### Copying Template Classes ###<br>
<br>
Since the construct is similar to inheritance, the syntax for
creating aliases<br>
of templated classes could be the same:<br>
<br>
```cpp<br>
template <typename T><br>
struct A {};<br>
<br>
template <typename T><br>
struct B : using A<T> {};<br>
<br>
B<int> b;<br>
```<br>
<br>
The copied class must have the same number or less of template
parameters than<br>
the base class. </span></div>
</blockquote>
Why do you introduce this restriction?<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><snip><span style=3D"font-family: courier
new,monospace;"><br>
<br>
### Copying Multiple Dependent Classes ###<br>
<br>
Copying multiple classes using the simple syntax we have
described can be<br>
impossible if those classes depend on one another. This is
because each copy<br>
would depend on the originals, rather than on the copied
classes. A possible way<br>
to specify such dependencies could be:<br>
<br>
```cpp<br>
struct A;<br>
<br>
struct B {<br>
=C2=A0=C2=A0=C2=A0 A * a;<br>
};<br>
<br>
struct A {<br>
=C2=A0=C2=A0=C2=A0 B b;<br>
};<br>
<br>
struct C;<br>
<br>
struct D : using B {<br>
=C2=A0=C2=A0=C2=A0 using class C =3D A; // **<br>
};<br>
<br>
struct C : using A {<br>
=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct C;<br>
<br>
struct D {<br>
=C2=A0=C2=A0=C2=A0 C * a;<br>
};<br>
<br>
struct C {<br>
=C2=A0=C2=A0=C2=A0 D b;<br>
};<br>
<br>
*/<br>
```<br>
<br>
`using class` has been used in order to disambiguate it from
normal `using`<br>
alias directive. `using class` is only valid when the left
hand side has been<br>
defined as a copy of the right hand side.<br>
</span></div>
</blockquote>
In ** above C has not yet defined as a copy<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
In case of a template base class using a template second
class, one could<br>
specify different copies for certain specializations;<br>
<br>
```cpp<br>
template <typename T><br>
struct A {};<br>
<br>
template <typename T><br>
struct B {<br>
=C2=A0=C2=A0=C2=A0 A<T> a;<br>
};<br>
<br>
template <typename T><br>
struct C : using A<T> {};<br>
<br>
```<br>
<br>
</span></div>
</blockquote>
I believe this interdependent case introduce a lot of complexity. We
would need a good use case to introduce it on the standard.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
###
Substituting Existing Functionality (Optional) ###<br>
<br>
</span></div>
</blockquote>
I believe that this cannot be optional as in a lot of cases we need
to modify/restrict the base type interface.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
Ideally
one may want to use most of an implementation for another
class, but<br>
vary a certain number of methods. In this case, if `Copy`
contains a member<br>
function that already exists in `Base`, then that
implementation is substituted<br>
in `Copy`. This may or may not be allowed for attributes.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>
};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n"; }<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n"; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>
};<br>
<br>
*/<br>
```<br>
<br>
A side effect of this is that it could allow for some type of
"interface", where<br>
some base class could be defined as:<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>
=C2=A0=C2=A0=C2=A0 void foo();<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
};<br>
<br>
struct Copy1 : using Base {<br>
=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>
=C2=A0=C2=A0=C2=A0 void baz();<br>
=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy1 {<br>
=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
=C2=A0=C2=A0=C2=A0 void baz();<br>
};<br>
<br>
*/<br>
<br>
struct Copy2 : using Base {<br>
=C2=A0=C2=A0=C2=A0 Copy2(int);<br>
=C2=A0=C2=A0=C2=A0 void abc();<br>
};<br>
<br>
/*<br>
<br>
Equivalent to<br>
<br>
struct Copy2 {<br>
=C2=A0=C2=A0=C2=A0 Copy2(int);<br>
=C2=A0=C2=A0=C2=A0 void foo();<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
=C2=A0=C2=A0=C2=A0 void abc();<br>
};<br>
<br>
*/<br>
```<br>
<br>
This feature could however present problems when the members
changed also alter<br>
behavior and/or variable types of non-modified member and
non-member functions,<br>
since the new behavior could be either erroneous or ambiguous.<br=
>
</span></div>
</blockquote>
Could you give a concrete example of this kind of problems?<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
### Copying and Extending Primitive Types (Optional) ###<br>
<br>
The same syntax could be used in order to extend primitive
types. Using the<br>
extension that allows the modification of the copied types,
this could allow for<br>
creation of numeric types where some operations are disabled
as needed.<br>
</span></div>
</blockquote>
<br>
Note the missing friend below<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
```cpp<br>
struct Id : using int {<br>
=C2=A0=C2=A0=C2=A0 <b>friend </b>Id operator+(Id, Id) =3D delete;=
<br>
=C2=A0=C2=A0=C2=A0 </span><span style=3D"font-family: courier new=
,monospace;"><span
style=3D"font-family: courier new,monospace;"><b>friend </b></s=
pan>Id
operator*(Id, Id) =3D delete;<br>
=C2=A0=C2=A0=C2=A0 // Non-explicitly deleted operators keep their=
validity<br>
<br>
</span></div>
</blockquote>
While this is inline with your approach, this merits some
explanations as the operators are no members. Shouldn't the
operators of UDT classes meritt to be inherited as well?<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
=C2=A0=C2=A0=C2=A0
// Defining new operators with the old type can allow
interoperativity<br>
=C2=A0=C2=A0=C2=A0 </span><span style=3D"font-family: courier new=
,monospace;"><span
style=3D"font-family: courier new,monospace;"><b>friend </b></s=
pan>Id
operator+(Id, int);<br>
=C2=A0=C2=A0=C2=A0 // We can convert the copied type to the old o=
ne.<br>
=C2=A0=C2=A0=C2=A0 operator int() { return (*this) * 2; }<br>
};<br>
<br>
</span></div>
</blockquote>
I believed that there where no implicit conversions on your
proposals. How (*this) is converted to an int?<br>
<br>
What would be the result type of x below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<br>
<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
/*
Equivalent to<br>
<br>
class Id final {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator/(Id lhs, I=
d rhs) { return Id{lhs.v_ /
rhs.v_}; }<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, I=
d rhs) { return Id{lhs.v_ -
rhs.v_}; }<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { retur=
n v_ * 2; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>
};<br>
<br>
*/<br>
```<br>
<br>
Note that when copying from a primitive types inheritance is
forbidden as the<br>
generated copy is `final` (although it is allowed to keep
copying the newly<br>
created class).<br>
</span></div>
</blockquote>
Why this restriction is needed or desirable.<br>
<blockquote
cite=3D"mid:fd8eda2b-182f-4e32-8fda-c7f728e22fa2@isocpp.org"
type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family: courier new,monospace;">=
<br>
### STL Traits (Optional) ###<br>
<br>
Traits could be included in the standard library in order to
determine whether a<br>
class is a copy of another, or if it has been derived from a
copy<br>
(copies/inheritances could be nested arbitrarily).<br>
<br>
```cpp<br>
struct Base {};<br>
<br>
struct Copy : using Base {};<br>
<br>
static_assert(std::is_copy<Copy, Base>::value);<br>
<br>
struct ChildCopy : public Copy {};<br>
<br>
struct CopyChildCopy : using ChildCopy {};<br>
<br>
static_assert(std::is_copy_base_of<Base,
CopyChildCopy>::value);<br>
```<br>
<br>
</span></div>
</blockquote>
Example of where this can be useful welcome.<br>
<br>
How other type traits behave for the copied class (see p0109r0)?<br>
<br>
<br>
In summary, I believe that<br>
<br>
Vicente<br>
<br>
[p0109r0]
<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2015/p0109r0.pdf">http://www.open-std.org/jtc1/sc22/=
wg21/docs/papers/2015/p0109r0.pdf</a><br>
<br>
[TBoost.Opaque]
<a class=3D"moz-txt-link-freetext" href=3D"https://htmlpreview.github.io/?h=
ttps://github.com/viboes/opaque/blob/master/libs/opaque/doc/html/index.html=
">https://htmlpreview.github.io/?https://github.com/viboes/opaque/blob/mast=
er/libs/opaque/doc/html/index.html</a><br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9574d1c1-b3ff-b9ae-ceee-908a2b983278%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/9574d1c1-b3ff-b9ae-ceee-908a2b983278=
%40wanadoo.fr</a>.<br />
--------------7DED0E8F175F195436D6A87B--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Sat, 31 Dec 2016 15:57:40 +0100
Raw View
--94eb2c0412765201970544f58afd
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vincente,
Thank you for your very in-depth review. I've updated the proposal using
already received comments from this thread, so some things have changed,
but it's still alright to receive comments on this version. I'll explain
below how it has changed when answering to your comments.
IIUC, every occurrence of the base type in the definition of the base type
> is replaced by the new type. This is one of the options described in Opaq=
ue
> proposal (see The return type issue). Why the other alternatives have les=
s
> sens?
>
There are many differences between my proposal and the Opaque proposal. I
believe that the main ones that this proposal brings are:
- Where possible, do not introduce new meanings or rules to the language.
The type-copied class should behave as closely as possible to a class the
user has implemented by hand. This should make very easy to understand how
the feature works, without the need to grasp many new concepts.
- I have removed the option to modify and remove existing functionality
from the class that is being copied. While I believe that this can be
useful, it introduces too much complexity in my opinion now. If this is
allowed, you basically have to create a system where you are allowed to
completely rewrite an existing class starting from another, since you may
want to copy or remove or change anything that was previously present. This
I believe can both make the proposal unnecessary complicated, and can make
the code very hard to follow, as at each new strong-typedef step (since a
type could be copied, and the copy copied again and so on) anything could
happen. I now believe that an incremental-only strategy (similar to
inheritance) can still be both useful and sufficient for most cases. Where
it is not, simple implementations by hand of basic functionality, extended
then via the type-copy mechanism should result in clear, reusable code
which still requires little maintenance.
The word duplicating and wrapping don't match. The proposed approach
> doesn't wraps the underlying type, except maybe for builtin types.
>
Right, I'll fix it, thanks.
I believe the proposal needs to add some concrete examples as use cases
>
This makes sense, I'll worn ok an additional section where I try to show
some concrete examples.
If the base class change, the strong types depending on it could need
> maintenance also, isn't it?
>
True, however wrapper methods have to be fixed 100% of the time, while a
type-copied class may not need this. It's the same as if one modified a
base class in inheritance - you don't have to necessarily update all the
code that depends on it right away.
In addition to these basic techniques, there are other library solution, as
> e.g. using CRTP that might merit to be mentioned.
> See [TBoost.Opaque] for a possible implementation.
>
I'll add a mention to CRTP. I'll give a look at the boost link, thanks!
Please add http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p010
> 9r0.pdf to this list.
>
Thanks, I must have missed it.
What is wrong for you with p0109r0 approach?
> What we could have with your approach that we cannot have with p0109r0?
> What we could have with p0109r0 that we cannot have with your approach?
>
> IIUC, p0109r0 opaque types don't introduce any operations by default othe=
r
> than conversions and your proposal introduce all members but no friends
>
Personally, I don't think there's anything "wrong" with p0109r0. The idea
for this proposal came to me before I knew the alternatives, but since C++
still does not have strong typedefs I thought I might as well propose an
alternative approach, which could possibly garner more interest.
I believe my approach is simpler to read and more intuitive - especially
when creating strong aliases of very complex types, but that can definitely
be bias. It can be applied to hierarchies of classes, since it allows
type-copying interdependent classes, which I believe is very important. It
is very easy to use with templates and specializations, which potentially
gives it a lot of power and very many potential uses. It is easily
composable, as in copying a copy is very easy and indeed expected in my
view for the feature.
With p0109r0 there's more flexibility to alter a type. The additional
flexibility allows it to take on more tasks, as in type-copying friends,
since default ways to convert to the original types exist. It is designed
for primitive types first, while I have actually removed them in my last
iteration for a number of reasons (see below). The additional flexibility
however comes at a cost, as you mention the return type issue, which my
proposal does not have.
I don't introduce friends mostly because a feature to create type-aliases
of methods does not currently exist, and I don't believe it is wise to add
it to the scope of this proposal since it would be another very large
change. If such a feature existed, however, adding friends to a type-copied
class in my proposal would be trivial, as simply strong typedefs of the
needed functions could be created on the fly. The same could also be done
for non-member functions if needed, but how that would work I have not
thought about yet.
I find that conversions to/from the underlying type must be covered by the
> proposal. If we change the Base type we don't want to be forced to redefi=
ne
> the conversion operator.
> Maybe we need some kind of default conversion implementation
> operator Base() *=3D default*;
> or
> *explicit* operator Base() *=3D default*;
>
I like this. I didn't add it to keep the number of features as low as
reasonably possible, but this is simple enough. This could also be used
recursively, as in a copy of a copy could define a conversion operator to
both the first copy and the original in this way. However, this default way
to define a conversion operator would be disabled if the copy has added new
attributes with respect to its original class.
Why do you introduce this restriction? (on template parameter numbers)
>
No actually, you're right. I should lift it. I thought initially that there
wouldn't be any reason to add more template parameters, as they would only
be needed to satisfy the original class. But this is definitely wrong. I'll
change it, thanks.
In ** above C has not yet defined as a copy
>
Ill explain how I believe this example should work. Since C has been
declared but not defined when parsing D, the compiler will be allowed to
assume that C is going to be defined later as a type-copy of A. If that
does not happen, then the compiler will give an error, either at the
definition of C or of D, explaining that D assumed that C would have been a
type-copy while it was not. If C has added new attributes to its
declaration though D's definition would need to take the new size of C into
account though. Not sure if this can be done or if it should result in an
error.
I believe this interdependent case introduce a lot of complexity. We would
> need a good use case to introduce it on the standard.
>
A very simple example would be copying of inherited classes, both base and
derived. Without a way to do this that just cannot be done. This can be
important if one does not want that the derived type and its type-copy are
allowed to be converted to the same base. This is a strong reason, I
believe, otherwise strong-typing in that case just lost some power in
keeping original and type-copy apart.
I believe that this cannot be optional as in a lot of cases we need to
> modify/restrict the base type interface.
>
I have actually removed this in my newest revision. I believe that
ground-up building of types is the better way to go (as is normally done in
inheritance). Having the power to completely alter the original type,
possibly to a point where there was not even much in common between the
original and the type-copy, is not worth it. This is a personal opinion,
but I believe doing so can prevent some very complex and ugly code smells,
at a not incredible cost.
Could you give a concrete example of this kind of problems?
>
Suppose
struct A {
int foo(int x) { return x * 2; }
double bar(double x) { return foo(x) * 4.0; }
};
struct B : using A {
int foo(int) =3D delete;
// bar cannot compile anymore
};
struct C : using A {
double foo(int x) { return x * 2; }
// ambiguous definition
};
struct D : using A {
double foo(double x) { return x * 3; }
// Changes meaning of bar underhandedly with no warning
};
I suppose even more dangerous and complex cases could be devised.
While this is inline with your approach, this merits some explanations as
> the operators are no members. Shouldn't the operators of UDT classes meri=
tt
> to be inherited as well?
>
I've removed primitive type support also for this reason. They are not
currently treated as classes by C++, and so I think I shouldn't either.
Instead my approach is now constructive. If one needed aliases for
primitive types, one could create a single header of wrappers in the form
template <typename T>
class SimpleWrapper {
public:
SimpleWrapper(T t) : t_(t) {}
private:
T t_;
};
template <typename T>
struct SimpleWrapperWithSum : using SimpleWrapper<T> {
SimpleWrapperWithSum operator+(const SimpleWrapperWithSum & other) {
return t_ + other.t_; }
};
And so on. It would only be needed once, and then users could simply copy
the versions with the operators they need to use. It's not incredibly
pretty and it does have some limitations, but it works, and in any case
even in p0109r0 one would need to remove all unneeded operators, so work
would need to be done anyway.
I believed that there where no implicit conversions on your proposals. How
> (*this) is converted to an int?
>
> What would be the result type of x below?
>
> Id id(1);
> auto x =3D +id;
>
> I suspect that it would be Id.
>
Yeah, this was a weird syntax, I thought it could be a simple way to
represent conversion to the underlying primitive type.
The type of the operation would be Id, yes. I believe that to be the only
intuitive result that makes sense, unless an explicit operator+ that does a
conversion has been defined somewhere. If a cast is needed, one needs to
cast. I don't see a reason to change that for strong typedefs, otherwise
the language would be inconsistent IMO.
Why this restriction is needed or desirable. (w.r.t. final in type-copies
> of primitive types)
>
It is not. But I believe that if one needs to do something, it has to be in
line with the rest of the language. If a strong typedef of a primitive type
is needed, it would still need to follow the rules of primitive types. As
primitive types are not inheritable, I believe neither should the strong
typedefs. Maybe this is a wrong position, I don't know (since primitive
typedefs are not inheritable due to C compatibilities IIUC), but I believe
that having consistency is still useful for a proposal. Otherwise one needs
to always learn a million exceptions to each rule, and that I don't like,
where it can be avoided. In any case, these are my opinions, but if there
is strong consensus to change how the proposal works I have no problem in
modifying it.
Example of where this can be useful welcome.
>
I must admit I didn't really think about this, I just thought they could be
nice to have. Maybe they would be useless. I just considered that sometimes
the ingenuity of how people use tools always seem to surprise, so why not.
Maybe in order to SFINAE the generation of conversion operators to classes,
given that they are copies of the original? Something like
struct Copy : using A {
template <typename T, /* enable_if_t<is_copy_of_v<T, A>>> */>
operator T =3D default;
};
How other type traits behave for the copied class (see p0109r0)?
>
All other type traits behave as if the class had been implemented by hand,
and is separate from the original. so is_same would return false, for
example. It seems that p0109r0 thinks the same way. The only difference is
that sizeof may be different, since in my proposal one could add additional
attributes to the type-copied class. (There's no examples in the old
version, I've added them on GitHub though).
Thanks again for your feedback.
Best,
Eugenio Bargiacchi
On Sat, Dec 31, 2016 at 12:14 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 19/12/2016 =C3=A0 12:04, svalorzen@gmail.com a =C3=A9crit :
>
> This is a stub proposal on strong typedefs, i.e. types that work in the
> exact same way, but allow separate overloading. Other papers and proposal=
s
> exist, but I've tried a different approach that tries to mimic a more
> inheritance-like syntax which might be more intuitive. The full text can =
be
> found online at https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.
> Thanks in advance for your comments.
>
> Hi,
>
> your proposal has the merit to propose a different approach. IIUC, you
> approach consists in introducing/duplicating all members (type, data,
> functions, constructors/destructors) from the underlying class, but no th=
e
> friends.
> p0109r0 introduce only conversions to/from the underlying type.
>
> IIUC, every occurrence of the base type in the definition of the base typ=
e
> is replaced by the new type. This is one of the options described in Opaq=
ue
> proposal (see The return type issue). Why the other alternatives have les=
s
> sens?
>
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing
> functionality
> while wrapping it in a new type, without the burden of inheritance and to
> allow
> function overloads on syntactically identical but semantically different
> types
> (also known as *strong typedef*).
>
> The word duplicating and wrapping don't match. The proposed approach
> doesn't wraps the underlying type, except maybe for builtin types.
>
>
>
> The approach taken should be simple to implement and be applicable to
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending on
> context
> have currently no simple way to indicate the semantic differences. Sinc=
e
> a
> `typedef` does not allow multiple overloads on new typedef types - sinc=
e
> they
> are still the "old" type - they have to resort to imperfect techniques,
> such
> as copying, wrapping or inheriting the needed type. Examples:
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather th=
an
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste
> alternative.
> This can result in very deep hierarchies of types which should really
> not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but
> partially
> extend it with context-specific methods. Examples: search for
> "`std::vector`
> inheritance" yields many results of users trying to maintain the origin=
al
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
> I believe the proposal needs to add some concrete examples as use cases
>
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type. However=
,
> this
> leaves no space to implement overloads that are context-specific. Nor a
> type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original interfac=
e
> in
> order to be able to duplicate it correctly. Template methods, rvalue
> references,
> possibly undocumented methods which are required in order to allow the
> class to
> behave in the same way as before. This heightens the bar significantly fo=
r
> many
> users, since they may not know correctly how to duplicate an interface an=
d
> how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
>
> If the base class change, the strong types depending on it could need
> maintenance also, isn't it?
>
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs
> discovered
> in one class must be fixed in the other class too. All new features
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and
> implementation
> of a given class just one time, and used multiple times to produce separa=
te
> classes.
>
> This approach is unfortunately not applicable to existing code, and is
> very hard
> to extend if one wants to copy a class but add additional functionality t=
o
> it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are
> unfortunately
> not applicable to previously existing code. For new code, they would
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible: variation=
s
> would
> need to be made through specialization, which itself requires copying
> existing
> code.
>
> In addition to these basic techniques, there are other library solution,
> as e.g. using CRTP that might merit to be mentioned.
> See [TBoost.Opaque] for a possible implementation.
>
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language multiple
> times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f
> ),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf
> ),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
> ),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are
> named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private` ar=
e
> used
> in order to create a specific relation with the original type and how is
> the
> new type allowed to be cast back to the original type or be used in its
> place
> during overloads.
>
> Please add http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p010
> 9r0.pdf to this list.
>
> This document shares many of the the same principles, for example (quotin=
g
> from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships such =
as
> > base classes underlying derived classes and integer types underlying
> enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We
> also do
> > not require that any enum type, reference type, array type, function
> type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple approach,
> where
> a new language feature is introduced with the same meaning and
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more simple
> to
> understand (as it simply matches already the already understood mechanics
> of
> creating a new, unique type from nothing), and no new rules for type
> conversion
> and selection on overloads have to be created.
>
> What is wrong for you with p0109r0 approach?
> What we could have with your approach that we cannot have with p0109r0?
> What we could have with p0109r0 that we cannot have with your approach?
>
> IIUC, p0109r0 opaque types don't introduce any operations by default othe=
r
> than conversions and your proposal introduce all members but no friends
>
>
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
> is this almost equivalent to p0109r0
>
> using Copy : private Base {
> using Base::foo; // if this was allowed in p0109r0
>
> };
>
>
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class is
> needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would
> inherit
> from the same classes its base class inherits from. All constructors woul=
d
> work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of Base,
> to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion operator=
s
> can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility were
> needed,
> one would only need to implement them once, since copying the produced ty=
pe
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
> I find that conversions to/from the underlying type must be covered by th=
e
> proposal. If we change the Base type we don't want to be forced to redefi=
ne
> the conversion operator.
> Maybe we need some kind of default conversion implementation
>
> operator Base() *=3D default*;
>
> or
>
> *explicit* operator Base() *=3D default*;
>
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
>
> Agree reinterpret_cast should be allowed.
>
>
> In general the usual rules of `reinterpret_cast` apply to the copied
> classes
> with respect to their general classes, exactly as if the copied class had
> been
> implemented by hand.
>
> <snip>
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template parameters
> than
> the base class.
>
> Why do you introduce this restriction?
>
> <snip>
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because each
> copy
> would depend on the originals, rather than on the copied classes. A
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A; // **
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal `usin=
g`
> alias directive. `using class` is only valid when the left hand side has
> been
> defined as a copy of the right hand side.
>
> In ** above C has not yet defined as a copy
>
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
> I believe this interdependent case introduce a lot of complexity. We woul=
d
> need a good use case to introduce it on the standard.
>
> ### Substituting Existing Functionality (Optional) ###
>
> I believe that this cannot be optional as in a lot of cases we need to
> modify/restrict the base type interface.
>
> Ideally one may want to use most of an implementation for another class,
> but
> vary a certain number of methods. In this case, if `Copy` contains a memb=
er
> function that already exists in `Base`, then that implementation is
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of "interface"=
,
> where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed also
> alter
> behavior and/or variable types of non-modified member and non-member
> functions,
> since the new behavior could be either erroneous or ambiguous.
>
> Could you give a concrete example of this kind of problems?
>
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types. Using t=
he
> extension that allows the modification of the copied types, this could
> allow for
> creation of numeric types where some operations are disabled as needed.
>
>
> Note the missing friend below
>
> ```cpp
> struct Id : using int {
> *friend *Id operator+(Id, Id) =3D delete;
> *friend *Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
> While this is inline with your approach, this merits some explanations as
> the operators are no members. Shouldn't the operators of UDT classes meri=
tt
> to be inherited as well?
>
> // Defining new operators with the old type can allow interoperativit=
y
> *friend *Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
> I believed that there where no implicit conversions on your proposals. Ho=
w
> (*this) is converted to an int?
>
> What would be the result type of x below?
>
> Id id(1);
> auto x =3D +id;
>
> I suspect that it would be Id.
>
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden as
> the
> generated copy is `final` (although it is allowed to keep copying the new=
ly
> created class).
>
> Why this restriction is needed or desirable.
>
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
> Example of where this can be useful welcome.
>
> How other type traits behave for the copied class (see p0109r0)?
>
>
> In summary, I believe that
>
> Vicente
>
> [p0109r0] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p010
> 9r0.pdf
>
> [TBoost.Opaque] https://htmlpreview.github.io/
> ?https://github.com/viboes/opaque/blob/master/libs/opaque/
> doc/html/index.html
>
> --
> 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/is
> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/is
> ocpp.org/d/msgid/std-proposals/9574d1c1-b3ff-b9ae-ceee-
> 908a2b983278%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/9574d1c1-b3=
ff-b9ae-ceee-908a2b983278%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2Bt0MkFNY4h%3DcrQWvh%3DJT2nHt5k_LWnO%3D=
SzgGkL2Q%3D_bSw%40mail.gmail.com.
--94eb2c0412765201970544f58afd
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div><div><div>Dear Vincente,<br><br></div>Thank you =
for your very in-depth review. I've updated the proposal using already =
received comments from this thread, so some things have changed, but it'=
;s still alright to receive comments on this version. I'll explain belo=
w how it has changed when answering to your comments.<br><br><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid=
rgb(204,204,204);padding-left:1ex">IIUC, every occurrence of the base type=
in the definition of the
base type is replaced by the new type. This is one of the options
described in Opaque proposal (see The return type issue). Why the
other alternatives have less sens?<span class=3D"m_-5826156030849956333=
gmail-im"></span><br><span class=3D"m_-5826156030849956333gmail-im"></span>=
</blockquote><span class=3D"m_-5826156030849956333gmail-im">
</span><br></div>There are many differences between my proposal and the=
Opaque proposal. I believe that the main ones that this proposal brings ar=
e:<br><br></div>- Where possible, do not introduce new meanings or rules to=
the language. The type-copied class should behave as closely as possible t=
o a class the user has implemented by hand. This should make very easy to u=
nderstand how the feature works, without the need to grasp many new concept=
s.<br></div>- I have removed the option to modify and remove existing funct=
ionality from the class that is being copied. While I believe that this can=
be useful, it introduces too much complexity in my opinion now. If this is=
allowed, you basically have to create a system where you are allowed to co=
mpletely rewrite an existing class starting from another, since you may wan=
t to copy or remove or change anything that was previously present. This I =
believe can both make the proposal unnecessary complicated, and can make th=
e code very hard to follow, as at each new strong-typedef step (since a typ=
e could be copied, and the copy copied again and so on) anything could happ=
en. I now believe that an incremental-only strategy (similar to inheritance=
) can still be both useful and sufficient for most cases. Where it is not, =
simple implementations by hand of basic functionality, extended then via th=
e type-copy mechanism should result in clear, reusable code which still req=
uires little maintenance.<br><br><div><div><div><blockquote class=3D"gmail_=
quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,=
204);padding-left:1ex">The word duplicating and wrapping don't match. T=
he proposed approach
doesn't wraps the underlying type, except maybe for builtin types.<=
br></blockquote><br></div><div>Right, I'll fix it, thanks.<br><br><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex">I believe the proposal needs t=
o add some concrete examples as use
cases<br></blockquote></div><div><br></div><div>This makes sense, I'=
;ll worn ok an additional section where I try to show some concrete example=
s.<br></div><div><br><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">If t=
he base class change, the strong types depending on it could
need maintenance also, isn't it?<span class=3D"m_-58261560308499563=
33gmail-im"><br></span></blockquote><div><br></div><div>True, however wrapp=
er methods have to be fixed 100% of the time, while a type-copied class may=
not need this. It's the same as if one modified a base class in inheri=
tance - you don't have to necessarily update all the code that depends =
on it right away.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">=
In addition to these basic techniques, there are other library
solution, as e.g. using CRTP that might merit to be mentioned.<br>
See [TBoost.Opaque] for a possible implementation.<span class=3D"m_-582=
6156030849956333gmail-im"></span><br><span class=3D"m_-5826156030849956333g=
mail-im"></span></blockquote><br> </div><div>I'll add a mention to CRTP=
.. I'll give a look at the boost link, thanks!<br><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex">Please add
<a class=3D"m_-5826156030849956333gmail-m_-7522649930861642754moz-txt-l=
ink-freetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/20=
15/p0109r0.pdf" target=3D"_blank">http://www.open-std.org/jtc1/s<wbr>c22/wg=
21/docs/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span class=3D"m_-5826156030849956333gmail-im"></span><br>=
<span class=3D"m_-5826156030849956333gmail-im"></span></blockquote><br></di=
v><div>Thanks, I must have missed it.<br></div><div><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex">What is wrong for you with p0109r0 approac=
h?<br>
What we could have with your approach that we cannot have with
p0109r0?<br>
What we could have with p0109r0 that we cannot have with your
approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce any operations by defaul=
t
other than conversions and your proposal introduce all members but
no friends<span class=3D"m_-5826156030849956333gmail-im"></span><br><sp=
an class=3D"m_-5826156030849956333gmail-im"></span></blockquote><br></div><=
div>Personally, I don't think there's anything "wrong" wi=
th p0109r0. The idea for this proposal came to me before I knew the alterna=
tives, but since C++ still does not have strong typedefs I thought I might =
as well propose an alternative approach, which could possibly garner more i=
nterest.<br><br></div><div>I believe my approach is simpler to read and mor=
e intuitive - especially when creating strong aliases of very complex types=
, but that can definitely be bias. It can be applied to hierarchies of clas=
ses, since it allows type-copying interdependent classes, which I believe i=
s very important. It is very easy to use with templates and specializations=
, which potentially gives it a lot of power and very many potential uses. I=
t is easily composable, as in copying a copy is very easy and indeed expect=
ed in my view for the feature.<br><br></div><div>With p0109r0 there's m=
ore flexibility to alter a type. The additional flexibility allows it to ta=
ke on more tasks, as in type-copying friends, since default ways to convert=
to the original types exist. It is designed for primitive types first, whi=
le I have actually removed them in my last iteration for a number of reason=
s (see below). The additional flexibility however comes at a cost, as you m=
ention the return type issue, which my proposal does not have.<br><br></div=
><div>I don't introduce friends mostly because a feature to create type=
-aliases of methods does not currently exist, and I don't believe it is=
wise to add it to the scope of this proposal since it would be another ver=
y large change. If such a feature existed, however, adding friends to a typ=
e-copied class in my proposal would be trivial, as simply strong typedefs o=
f the needed functions could be created on the fly. The same could also be =
done for non-member functions if needed, but how that would work I have not=
thought about yet.<br><br><blockquote class=3D"gmail_quote" style=3D"margi=
n:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex=
">I find that conversions to/from the underlying type must be covered
by the proposal. If we change the Base type we don't want to be
forced to redefine the conversion operator.<br>
Maybe we need some kind of default conversion implementation<br>
<span style=3D"font-family:courier new,monospace">=C2=A0=C2=A0=C2=A0 op=
erator
Base() <b>=3D default</b>;</span><br><span style=3D"font-family:couri=
er new,monospace">
or </span><br>
<span style=3D"font-family:courier new,monospace">=C2=A0=C2=A0=C2=A0 <b=
>explicit</b>
operator Base() <b>=3D default</b>;</span><br></blockquote></div><div=
><br></div><div>I like this. I didn't add it to keep the number of feat=
ures as low as reasonably possible, but this is simple enough. This could a=
lso be used recursively, as in a copy of a copy could define a conversion o=
perator to both the first copy and the original in this way. However, this =
default way to define a conversion operator would be disabled if the copy h=
as added new attributes with respect to its original class.<br><br><blockqu=
ote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px=
solid rgb(204,204,204);padding-left:1ex">Why do you introduce this restric=
tion? (on template parameter numbers)<br></blockquote></div><div><br></div>=
<div>No actually, you're right. I should lift it. I thought initially t=
hat there wouldn't be any reason to add more template parameters, as th=
ey would only be needed to satisfy the original class. But this is definite=
ly wrong. I'll change it, thanks.<br></div><div><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex">In ** above C has not yet defined as a cop=
y<span class=3D"m_-5826156030849956333gmail-im"></span><br><span class=3D"m=
_-5826156030849956333gmail-im"></span></blockquote><br></div><div>Ill expla=
in how I believe this example should work. Since C has been declared but no=
t defined when parsing D, the compiler will be allowed to assume that C is =
going to be defined later as a type-copy of A. If that does not happen, the=
n the compiler will give an error, either at the definition of C or of D, e=
xplaining that D assumed that C would have been a type-copy while it was no=
t. If C has added new attributes to its declaration though D's definiti=
on would need to take the new size of C into account though. Not sure if th=
is can be done or if it should result in an error.<br></div><div><br><block=
quote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1=
px solid rgb(204,204,204);padding-left:1ex">I believe this interdependent c=
ase introduce a lot of complexity. We
would need a good use case to introduce it on the standard.<span class=
=3D"m_-5826156030849956333gmail-im"></span><br><span class=3D"m_-5826156030=
849956333gmail-im"></span></blockquote><br></div><div>A very simple example=
would be copying of inherited classes, both base and derived. Without a wa=
y to do this that just cannot be done. This can be important if one does no=
t want that the derived type and its type-copy are allowed to be converted =
to the same base. This is a strong reason, I believe, otherwise strong-typi=
ng in that case just lost some power in keeping original and type-copy apar=
t.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I believe that =
this cannot be optional as in a lot of cases we need
to modify/restrict the base type interface.<br></blockquote><br></div><=
div>I have actually removed this in my newest revision. I believe that grou=
nd-up building of types is the better way to go (as is normally done in inh=
eritance). Having the power to completely alter the original type, possibly=
to a point where there was not even much in common between the original an=
d the type-copy, is not worth it. This is a personal opinion, but I believe=
doing so can prevent some very complex and ugly code smells, at a not incr=
edible cost.<br></div><div><br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex"><div>Could you give a concrete example of this kind of problems=
?<br></div></blockquote><div><div style=3D"margin-left:40px"><span class=3D=
"m_-5826156030849956333gmail-im"></span></div><br></div><div>Suppose<br><br=
></div><div>struct A {<br></div><div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x=
) { return x * 2; }<br></div><div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(doubl=
e x) { return foo(x) * 4.0; }<br>};<br></div><div><br></div><div>struct B :=
using A {<br></div><div>=C2=A0=C2=A0=C2=A0 int foo(int) =3D delete;<br></d=
iv><div>=C2=A0=C2=A0=C2=A0 // bar cannot compile anymore<br></div><div>};<b=
r><br></div><div>struct C : using A {<br></div><div>=C2=A0=C2=A0=C2=A0 doub=
le foo(int x) { return x * 2; }<br></div><div>=C2=A0=C2=A0=C2=A0 // ambiguo=
us definition<br>};<br></div><div><br></div><div>struct D : using A {<br></=
div><div>=C2=A0=C2=A0=C2=A0 double foo(double x) { return x * 3; }<br></div=
><div>=C2=A0=C2=A0=C2=A0 // Changes meaning of bar underhandedly with no wa=
rning<br></div><div>};<br><br></div><div>I suppose even more dangerous and =
complex cases could be devised.<br></div><div><br><blockquote class=3D"gmai=
l_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,20=
4,204);padding-left:1ex">While this is inline with your approach, this meri=
ts some
explanations as the operators are no members. Shouldn't the
operators of UDT classes meritt to be inherited as well?<br></blockquot=
e><div><br></div><div>I've removed primitive type support also for this=
reason. They are not currently treated as classes by C++, and so I think I=
shouldn't either. Instead my approach is now constructive. If one need=
ed aliases for primitive types, one could create a single header of wrapper=
s in the form<br><br></div><div>template <typename T><br></div><div>c=
lass SimpleWrapper {<br></div><div>=C2=A0=C2=A0=C2=A0 public:<br></div><div=
>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 SimpleWrapper(T t) : t_(t) {}<b=
r><br></div><div>=C2=A0=C2=A0=C2=A0 private:<br></div><div>=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br></div><div>};<br><br></div><div>templa=
te <typename T><br></div><div>struct SimpleWrapperWithSum : using Sim=
pleWrapper<T> {<br></div><div>=C2=A0=C2=A0=C2=A0 SimpleWrapperWithSum=
operator+(const SimpleWrapperWithSum & other) { return t_ + other.t_; =
}<br></div><div>};<br><br></div><div>And so on. It would only be needed onc=
e, and then users could simply copy the versions with the operators they ne=
ed to use. It's not incredibly pretty and it does have some limitations=
, but it works, and in any case even in p0109r0 one would need to remove al=
l unneeded operators, so work would need to be done anyway. <br><br></div><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><div>I believed that there=
where no implicit conversions on your
proposals. How (*this) is converted to an int?<br>
<br>
What would be the result type of x below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span class=3D"m_-5826156030849956333gmai=
l-im"></span><br></div></blockquote><div><blockquote><span class=3D"m_-5826=
156030849956333gmail-im"></span></blockquote>Yeah, this was a weird syntax,=
I thought it could be a simple way to represent conversion to the underlyi=
ng primitive type.<br><br>The type of the operation would be Id, yes. I bel=
ieve that to be the only intuitive result that makes sense, unless an expli=
cit operator+ that does a conversion has been defined somewhere. If a cast =
is needed, one needs to cast. I don't see a reason to change that for s=
trong typedefs, otherwise the language would be inconsistent IMO.<br><br><b=
lockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-le=
ft:1px solid rgb(204,204,204);padding-left:1ex">Why this restriction is nee=
ded or desirable.<span class=3D"m_-5826156030849956333gmail-im"> (w.r.t. fi=
nal in type-copies of primitive types)<br></span></blockquote><div><br></di=
v><div>It is not. But I believe that if one needs to do something, it has t=
o be in line with the rest of the language. If a strong typedef of a primit=
ive type is needed, it would still need to follow the rules of primitive ty=
pes. As primitive types are not inheritable, I believe neither should the s=
trong typedefs. Maybe this is a wrong position, I don't know (since pri=
mitive typedefs are not inheritable due to C compatibilities IIUC), but I b=
elieve that having consistency is still useful for a proposal. Otherwise on=
e needs to always learn a million exceptions to each rule, and that I don&#=
39;t like, where it can be avoided. In any case, these are my opinions, but=
if there is strong consensus to change how the proposal works I have no pr=
oblem in modifying it.<br><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex">Example of where this can be useful welcome.<br></blockquote><div><br>=
</div><div>I must admit I didn't really think about this, I just though=
t they could be nice to have. Maybe they would be useless. I just considere=
d that sometimes the ingenuity of how people use tools always seem to surpr=
ise, so why not. Maybe in order to SFINAE the generation of conversion oper=
ators to classes, given that they are copies of the original? Something lik=
e<br><br></div><div>struct Copy : using A {<br></div><div>=C2=A0=C2=A0=C2=
=A0=C2=A0 template <typename T, /* enable_if_t<is_copy_of_v<T, A&g=
t;>> */><br></div><div>=C2=A0=C2=A0=C2=A0=C2=A0 operator T =3D def=
ault;<br></div><div>};<br></div><div><br><blockquote class=3D"gmail_quote" =
style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);pa=
dding-left:1ex">How other type traits behave for the copied class (see p010=
9r0)?<br></blockquote>
<br></div><div>All other type traits behave as if the class had been im=
plemented by hand, and is separate from the original. so is_same would retu=
rn false, for example. It seems that p0109r0 thinks the same way. The only =
difference is that sizeof may be different, since in my proposal one could =
add additional attributes to the type-copied class. (There's no example=
s in the old version, I've added them on GitHub though).<br><br></div><=
div>Thanks again for your feedback.<br><br></div><div>Best,<br></div><div>E=
ugenio Bargiacchi<br></div></div></div></div></div></div></div><div class=
=3D"gmail_extra"><br><div class=3D"gmail_quote">On Sat, Dec 31, 2016 at 12:=
14 PM, Vicente J. Botet Escriba <span dir=3D"ltr"><<a href=3D"mailto:vic=
ente.botet@wanadoo.fr" target=3D"_blank">vicente.botet@wanadoo.fr</a>></=
span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8e=
x;border-left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span>
<div class=3D"m_-5826156030849956333m_-7522649930861642754moz-cite-pref=
ix">Le 19/12/2016 =C3=A0 12:04,
<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-link-=
abbreviated" href=3D"mailto:svalorzen@gmail.com" target=3D"_blank">svalorze=
n@gmail.com</a> a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">This is a stub proposal on strong typedefs, i.e.
types that work in the exact same way, but allow separate
overloading. Other papers and proposals exist, but I've tried a
different approach that tries to mimic a more inheritance-like
syntax which might be more intuitive. The full text can be found
online at <a href=3D"https://github.com/Svalorzen/CppCopyProposal" =
target=3D"_blank">https://github.com/Svalorzen/C<wbr>ppCopyProposal.<br>
<br>
</a>I'm copying the text below. Thanks in advance for your
comments.<br>
</div>
</blockquote></span>
Hi,<br>
<br>
your proposal has the merit to propose a different approach. IIUC,
you approach consists in introducing/duplicating all members (type,
data, functions, constructors/destructors) from the underlying
class, but no the friends.<br>
p0109r0 introduce only conversions to/from the underlying type.<br>
<br>
IIUC, every occurrence of the base type in the definition of the
base type is replaced by the new type. This is one of the options
described in Opaque proposal (see The return type issue). Why the
other alternatives have less sens?<span><br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><br>
<span style=3D"font-family:courier new,monospace">Duplication
and Extension of Existing Classes<br>
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D<br>
<br>
Introduction<br>
------------<br>
<br>
This document describes a possible approach to duplicate
existing functionality<br>
while wrapping it in a new type, without the burden of
inheritance and to allow<br>
function overloads on syntactically identical but semantically
different types<br>
(also known as *strong typedef*).<br>
<br>
</span></div>
</blockquote></span>
The word duplicating and wrapping don't match. The proposed approac=
h
doesn't wraps the underlying type, except maybe for builtin types.<=
div><div class=3D"m_-5826156030849956333h5"><br>
=C2=A0<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">Th=
e
approach taken should be simple to implement and be applicable
to existing<br>
code.<br>
<br>
Optional sections are to be read as additional ideas that
could be further<br>
developed or completely ignored. They are mostly food for
thought, but included<br>
for completeness.<br>
<br>
Reasons<br>
-------<br>
<br>
- Scientific libraries where a type has different behaviors
depending on context<br>
=C2=A0 have currently no simple way to indicate the semantic
differences. Since a<br>
=C2=A0 `typedef` does not allow multiple overloads on new typedef
types - since they<br>
=C2=A0 are still the "old" type - they have to resort t=
o imperfect
techniques, such<br>
=C2=A0 as copying, wrapping or inheriting the needed type.
Examples: coordinates in a<br>
=C2=A0 plane (rectangular, polar), vectors of double
(probabilities, values).<br>
- Easier maintainability of code which is known to be the
same, rather than<br>
=C2=A0 being copy-pasted.<br>
- Avoiding misuse of inheritance in order to provide a
copy-paste alternative.<br>
=C2=A0 This can result in very deep hierarchies of types which
should really not have<br>
=C2=A0 anything to do with each other.<br>
- Enabling users to use an existing and presumably correct
type but partially<br>
=C2=A0 extend it with context-specific methods. Examples: search
for "`std::vector`<br>
=C2=A0 inheritance" yields many results of users trying to m=
aintain
the original<br>
=C2=A0 interface and functionality but add one or two methods.<br=
>
<br>
The functionality should have the following requirements:<br>
<br>
- Can be applied to existing code.<br>
- Should limit dependencies between new and old type as much
as possible.<br>
- Should allow for partial extensions of the old code.<br>
<br>
</span></div>
</blockquote></div></div>
I believe the proposal needs to add some concrete examples as use
cases<span><br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">Al=
ternatives<br>
------------<br>
<br>
### Typedef / Using Directive ###<br>
<br>
Using a type alias creates an alternative name for a single
type. However, this<br>
leaves no space to implement overloads that are
context-specific. Nor a type can<br>
be extended in a simple way while keeping the old interface
intact.<br>
<br>
### Inheritance ###<br>
<br>
Inheritance requires redefinition of all constructors, and
creates a stricter<br>
dependency between two classes than what is proposed here.
Classes may be<br>
converted to a common ancestor even though that is undesired
or even dangerous<br>
in case of implicit conversions.<br>
<br>
Inheritance may also be unwanted in order to avoid risks
linked to polymorphism<br>
and freeing data structures where the base class does not have
a virtual<br>
destructor.<br>
<br>
### Encapsulation with Manual Exposure of Needed Methods ###<br>
<br>
This method obviously requires a great deal of code to be
rewritten in order to<br>
wrap every single method that the old class was exposing.<br>
<br>
In addition one needs to have intimate knowledge of the
original interface in<br>
order to be able to duplicate it correctly. Template methods,
rvalue references,<br>
possibly undocumented methods which are required in order to
allow the class to<br>
behave in the same way as before. This heightens the bar
significantly for many<br>
users, since they may not know correctly how to duplicate an
interface and how<br>
to forward parameters to the old interface correctly.<br>
<br>
The new code also must be maintained in case the old interface
changes.<br>
</span></div>
</blockquote></span>
If the base class change, the strong types depending on it could
need maintenance also, isn't it?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><b=
r>
### Copying the Base Class ###<br>
<br>
This can be useful, but requires all code to be duplicated,
and thus<br>
significantly increases the burden of maintaining the code.
All bugs discovered<br>
in one class must be fixed in the other class too. All new
features applied to<br>
one class must be applied to the other too.<br>
<br>
### Macro-expansion ###<br>
<br>
Macro expansions can be used in order to encode the interface
and implementation<br>
of a given class just one time, and used multiple times to
produce separate<br>
classes.<br>
<br>
This approach is unfortunately not applicable to existing
code, and is very hard<br>
to extend if one wants to copy a class but add additional
functionality to it.<br>
<br>
### Templates ###<br>
<br>
Templates produce for each instantiation a separate type. They
are unfortunately<br>
not applicable to previously existing code. For new code, they
would require the<br>
creation of "fake" template parameters that would need =
to vary
in order to<br>
produce separate types.<br>
<br>
In addition, class extension through templates is not
possible: variations would<br>
need to be made through specialization, which itself requires
copying existing<br>
code.<br>
<br>
</span></div>
</blockquote></span>
In addition to these basic techniques, there are other library
solution, as e.g. using CRTP that might merit to be mentioned.<br>
See [TBoost.Opaque] for a possible implementation.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">Pr=
evious
Work<br>
-------------<br>
<br>
Strong typedefs have already been proposed for the C++
language multiple times<br>
([N1706](<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-li=
nk-freetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/200=
4/n1706.pdf" target=3D"_blank">http://www.open-std.o<wbr>rg/jtc1/sc22/wg21/=
docs/papers/<wbr>2004/n1706.pdf</a>),<br>
[N1891](<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-lin=
k-freetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005=
/n1891.pdf" target=3D"_blank">http://www.open-std.or<wbr>g/jtc1/sc22/wg21/d=
ocs/papers/<wbr>2005/n1891.pdf</a>),<br>
[N3515](<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-lin=
k-freetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013=
/n3515.pdf" target=3D"_blank">http://www.open-std.or<wbr>g/jtc1/sc22/wg21/d=
ocs/papers/<wbr>2013/n3515.pdf</a>),<br>
[N3741](<a class=3D"m_-5826156030849956333m_-7522649930861642754m=
oz-txt-link-freetext" href=3D"https://isocpp.org/files/papers/n3741.pdf" ta=
rget=3D"_blank">https://isocpp.org/fil<wbr>es/papers/n3741.pdf</a>)). These
typedefs are named<br>
*opaque typedefs*, and these papers try to explore and define
exactly the<br>
behavior that such typedefs should and would have when used to
create new<br>
types. In particular, the keywords `public`, `protected` and
`private` are used<br>
in order to create a specific relation with the original type
and how is the<br>
new type allowed to be cast back to the original type or be
used in its place<br>
during overloads.<br>
<br>
</span></div>
</blockquote></span>
Please add
<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-link-fr=
eetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p01=
09r0.pdf" target=3D"_blank">http://www.open-std.org/jtc1/s<wbr>c22/wg21/doc=
s/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">Th=
is
document shares many of the the same principles, for example
(quoting from<br>
N3741):<br>
<br>
> - Consistent with restrictions imposed on analogous
relationships such as<br>
>=C2=A0=C2=A0 base classes underlying derived classes and inte=
ger
types underlying enums,<br>
>=C2=A0=C2=A0 an underlying type should be (1) complete and (2=
) not
cv-quali=EF=AC=81ed. We also do<br>
>=C2=A0=C2=A0 not require that any enum type, reference type, =
array
type, function type, or<br>
>=C2=A0=C2=A0 pointer-to-member type be allowed as an underlyi=
ng
type.<br>
<br>
However, this document tries to propose a possibly more simple
approach, where<br>
a new language feature is introduced with the same meaning and
functionality as<br>
if the user autonomously implemented a new class him/herself,
matching the<br>
original type completely. Thus, it should result for the user
more simple to<br>
understand (as it simply matches already the already
understood mechanics of<br>
creating a new, unique type from nothing), and no new rules
for type conversion<br>
and selection on overloads have to be created.<br>
</span></div>
</blockquote></span>
What is wrong for you with p0109r0 approach?<br>
What we could have with your approach that we cannot have with
p0109r0?<br>
What we could have with p0109r0 that we cannot have with your
approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce any operations by defaul=
t
other than conversions and your proposal introduce all members but
no friends<span><br>
<br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><b=
r>
Syntax<br>
------<br>
<br>
### Simple Case ###<br>
<br>
Syntax could look something like this:<br>
<br>
```cpp<br>
class Base {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout=
<< "foo " << x
<< "\n"; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
};<br>
<br>
struct Copy : using Base {};<br>
<br>
</span></div>
</blockquote></span>
is this almost equivalent to p0109r0<br>
<br>
=C2=A0=C2=A0=C2=A0 using Copy : private Base {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 using Base::foo; // if this was a=
llowed in p0109r0<div><div class=3D"m_-5826156030849956333h5"><br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">/*
Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout=
<< "foo " << x
<< "\n"; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
};<br>
<br>
*/<br>
```<br>
<br>
One cannot copy a class and inherit at the same time. If such
a class is needed<br>
one would need to create it by hand with the desided
functionality and<br>
inheriting from the desired classes, as it would be done
normally.<br>
<br>
All method implementations would be the same. The copied class
would inherit<br>
from the same classes its base class inherits from. All
constructors would work<br>
in the same way.<br>
<br>
### Adding New Functionality ###<br>
<br>
Ideally one could specify additional methods, separate from
that of Base, to add<br>
upon the existing functionality.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n&qu=
ot;; }<br>
};<br>
<br>
struct Derived : public Base {};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&qu=
ot;; }<br>
};<br>
<br>
struct CopyDerived : using Derived {};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n&qu=
ot;; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&qu=
ot;; }<br>
};<br>
<br>
struct CopyDerived : public Base {};<br>
<br>
*/<br>
```<br>
<br>
Only new methods need to be implemented for that class.<br>
<br>
#### Interfacing with the Original Class ####<br>
<br>
In order to interface with the original class, simple
conversion operators can<br>
be added by the user explicitly at-will, in order to obtain
the desired<br>
interface. Note that if more types with this kind of
compatibility were needed,<br>
one would only need to implement them once, since copying the
produced type<br>
would copy the new, more compatible interface with it.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>
<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>
};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>
};<br>
```<br>
<br>
</span></div>
</blockquote></div></div>
I find that conversions to/from the underlying type must be covered
by the proposal. If we change the Base type we don't want to be
forced to redefine the conversion operator.<br>
Maybe we need some kind of default conversion implementation<br>
<br>
<span style=3D"font-family:courier new,monospace">=C2=A0=C2=A0=C2=A0 op=
erator
Base() <b>=3D default</b>;<br>
<br>
or <br>
</span><br>
<span style=3D"font-family:courier new,monospace">=C2=A0=C2=A0=C2=A0 <b=
>explicit</b>
operator Base() <b>=3D default</b>;<br>
</span><span>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">`r=
einterpret_cast`
may also be used to convert back to the original class,<br>
limited by the tool's already existing rules.<br>
</span></div>
</blockquote></span>
Agree reinterpret_cast should be allowed.<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><s=
pan><br>
In general the usual rules of `reinterpret_cast` apply to the
copied classes<br>
with respect to their general classes, exactly as if the
copied class had been<br>
implemented by hand.<br>
<br></span>
<snip><span><br>
<br>
### Copying Template Classes ###<br>
<br>
Since the construct is similar to inheritance, the syntax for
creating aliases<br>
of templated classes could be the same:<br>
<br>
```cpp<br>
template <typename T><br>
struct A {};<br>
<br>
template <typename T><br>
struct B : using A<T> {};<br>
<br>
B<int> b;<br>
```<br>
<br>
The copied class must have the same number or less of template
parameters than<br>
the base class. </span></span></div>
</blockquote>
Why do you introduce this restriction?<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><snip><span style=3D"font-family:courier new,m=
onospace"><span><br>
<br>
### Copying Multiple Dependent Classes ###<br>
<br>
Copying multiple classes using the simple syntax we have
described can be<br>
impossible if those classes depend on one another. This is
because each copy<br>
would depend on the originals, rather than on the copied
classes. A possible way<br>
to specify such dependencies could be:<br>
<br>
```cpp<br>
struct A;<br>
<br>
struct B {<br>
=C2=A0=C2=A0=C2=A0 A * a;<br>
};<br>
<br>
struct A {<br>
=C2=A0=C2=A0=C2=A0 B b;<br>
};<br>
<br>
struct C;<br>
<br>
struct D : using B {<br></span>
=C2=A0=C2=A0=C2=A0 using class C =3D A; // **<span><br>
};<br>
<br>
struct C : using A {<br>
=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct C;<br>
<br>
struct D {<br>
=C2=A0=C2=A0=C2=A0 C * a;<br>
};<br>
<br>
struct C {<br>
=C2=A0=C2=A0=C2=A0 D b;<br>
};<br>
<br>
*/<br>
```<br>
<br>
`using class` has been used in order to disambiguate it from
normal `using`<br>
alias directive. `using class` is only valid when the left
hand side has been<br>
defined as a copy of the right hand side.<br>
</span></span></div>
</blockquote>
In ** above C has not yet defined as a copy<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><b=
r>
In case of a template base class using a template second
class, one could<br>
specify different copies for certain specializations;<br>
<br>
```cpp<br>
template <typename T><br>
struct A {};<br>
<br>
template <typename T><br>
struct B {<br>
=C2=A0=C2=A0=C2=A0 A<T> a;<br>
};<br>
<br>
template <typename T><br>
struct C : using A<T> {};<br>
<br>
```<br>
<br>
</span></div>
</blockquote></span>
I believe this interdependent case introduce a lot of complexity. We
would need a good use case to introduce it on the standard.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">##=
#
Substituting Existing Functionality (Optional) ###<br>
<br>
</span></div>
</blockquote></span>
I believe that this cannot be optional as in a lot of cases we need
to modify/restrict the base type interface.<div><div class=3D"m_-582615=
6030849956333h5"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">Id=
eally
one may want to use most of an implementation for another
class, but<br>
vary a certain number of methods. In this case, if `Copy`
contains a member<br>
function that already exists in `Base`, then that
implementation is substituted<br>
in `Copy`. This may or may not be allowed for attributes.<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n&qu=
ot;; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&qu=
ot;; }<br>
};<br>
<br>
struct Copy : using Base {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n&qu=
ot;; }<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy {<br>
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n&qu=
ot;; }<br>
=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n&qu=
ot;; }<br>
};<br>
<br>
*/<br>
```<br>
<br>
A side effect of this is that it could allow for some type of
"interface", where<br>
some base class could be defined as:<br>
<br>
```cpp<br>
struct Base {<br>
=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>
=C2=A0=C2=A0=C2=A0 void foo();<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
};<br>
<br>
struct Copy1 : using Base {<br>
=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>
=C2=A0=C2=A0=C2=A0 void baz();<br>
=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>
};<br>
<br>
/* Equivalent to<br>
<br>
struct Copy1 {<br>
=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
=C2=A0=C2=A0=C2=A0 void baz();<br>
};<br>
<br>
*/<br>
<br>
struct Copy2 : using Base {<br>
=C2=A0=C2=A0=C2=A0 Copy2(int);<br>
=C2=A0=C2=A0=C2=A0 void abc();<br>
};<br>
<br>
/*<br>
<br>
Equivalent to<br>
<br>
struct Copy2 {<br>
=C2=A0=C2=A0=C2=A0 Copy2(int);<br>
=C2=A0=C2=A0=C2=A0 void foo();<br>
=C2=A0=C2=A0=C2=A0 void bar();<br>
=C2=A0=C2=A0=C2=A0 void abc();<br>
};<br>
<br>
*/<br>
```<br>
<br>
This feature could however present problems when the members
changed also alter<br>
behavior and/or variable types of non-modified member and
non-member functions,<br>
since the new behavior could be either erroneous or ambiguous.<br=
>
</span></div>
</blockquote></div></div>
Could you give a concrete example of this kind of problems?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><b=
r>
### Copying and Extending Primitive Types (Optional) ###<br>
<br>
The same syntax could be used in order to extend primitive
types. Using the<br>
extension that allows the modification of the copied types,
this could allow for<br>
creation of numeric types where some operations are disabled
as needed.<br>
</span></div>
</blockquote>
<br></span>
Note the missing friend below<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><s=
pan>```cpp<br>
struct Id : using int {<br></span>
=C2=A0=C2=A0=C2=A0 <b>friend </b>Id operator+(Id, Id) =3D delete;=
<br>
=C2=A0=C2=A0=C2=A0 </span><span style=3D"font-family:courier new,=
monospace"><span style=3D"font-family:courier new,monospace"><b>friend </b>=
</span>Id
operator*(Id, Id) =3D delete;<span><br>
=C2=A0=C2=A0=C2=A0 // Non-explicitly deleted operators keep their=
validity<br>
<br>
</span></span></div>
</blockquote>
While this is inline with your approach, this merits some
explanations as the operators are no members. Shouldn't the
operators of UDT classes meritt to be inherited as well?<br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><s=
pan>=C2=A0=C2=A0=C2=A0
// Defining new operators with the old type can allow
interoperativity<br></span>
=C2=A0=C2=A0=C2=A0 </span><span style=3D"font-family:courier new,=
monospace"><span style=3D"font-family:courier new,monospace"><b>friend </b>=
</span>Id
operator+(Id, int);<span><br>
=C2=A0=C2=A0=C2=A0 // We can convert the copied type to the old o=
ne.<br>
=C2=A0=C2=A0=C2=A0 operator int() { return (*this) * 2; }<br>
};<br>
<br>
</span></span></div>
</blockquote>
I believed that there where no implicit conversions on your
proposals. How (*this) is converted to an int?<br>
<br>
What would be the result type of x below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span><br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace">/*
Equivalent to<br>
<br>
class Id final {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator/(Id lhs, I=
d rhs) { return Id{lhs.v_ /
rhs.v_}; }<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, I=
d rhs) { return Id{lhs.v_ -
rhs.v_}; }<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { retur=
n v_ * 2; }<br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>
};<br>
<br>
*/<br>
```<br>
<br>
Note that when copying from a primitive types inheritance is
forbidden as the<br>
generated copy is `final` (although it is allowed to keep
copying the newly<br>
created class).<br>
</span></div>
</blockquote></span>
Why this restriction is needed or desirable.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><span style=3D"font-family:courier new,monospace"><b=
r>
### STL Traits (Optional) ###<br>
<br>
Traits could be included in the standard library in order to
determine whether a<br>
class is a copy of another, or if it has been derived from a
copy<br>
(copies/inheritances could be nested arbitrarily).<br>
<br>
```cpp<br>
struct Base {};<br>
<br>
struct Copy : using Base {};<br>
<br>
static_assert(std::is_copy<Cop<wbr>y, Base>::value);<br>
<br>
struct ChildCopy : public Copy {};<br>
<br>
struct CopyChildCopy : using ChildCopy {};<br>
<br>
static_assert(std::is_copy_bas<wbr>e_of<Base,
CopyChildCopy>::value);<br>
```<br>
<br>
</span></div>
</blockquote></span>
Example of where this can be useful welcome.<br>
<br>
How other type traits behave for the copied class (see p0109r0)?<br>
<br>
<br>
In summary, I believe that<br>
<br>
Vicente<br>
<br>
[p0109r0]
<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-link-fr=
eetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p01=
09r0.pdf" target=3D"_blank">http://www.open-std.org/jtc1/s<wbr>c22/wg21/doc=
s/papers/2015/p010<wbr>9r0.pdf</a><br>
<br>
[TBoost.Opaque]
<a class=3D"m_-5826156030849956333m_-7522649930861642754moz-txt-link-freete=
xt" href=3D"https://htmlpreview.github.io/?https://github.com/viboes/opaque=
/blob/master/libs/opaque/doc/html/index.html" target=3D"_blank">https://htm=
lpreview.github.io/<wbr>?https://github.com/viboes/opa<wbr>que/blob/master/=
libs/opaque/<wbr>doc/html/index.html</a><br>
</div><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9574d1c1-b3ff-b9ae-ceee-908a2b983278%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/std-proposals<wbr>/9574=
d1c1-b3ff-b9ae-ceee-<wbr>908a2b983278%40wanadoo.fr</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bt0MkFNY4h%3DcrQWvh%3DJT2nH=
t5k_LWnO%3DSzgGkL2Q%3D_bSw%40mail.gmail.com?utm_medium=3Demail&utm_source=
=3Dfooter">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAH=
fn%3D%2Bt0MkFNY4h%3DcrQWvh%3DJT2nHt5k_LWnO%3DSzgGkL2Q%3D_bSw%40mail.gmail.c=
om</a>.<br />
--94eb2c0412765201970544f58afd--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sat, 31 Dec 2016 18:15:24 +0100
Raw View
This is a multi-part message in MIME format.
--------------52A047125D7EFF2D8235B50C
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit :
> Dear Vincente,
>
> Thank you for your very in-depth review. I've updated the proposal=20
> using already received comments from this thread, so some things have=20
> changed, but it's still alright to receive comments on this version.=20
> I'll explain below how it has changed when answering to your comments.
>
> IIUC, every occurrence of the base type in the definition of the
> base type is replaced by the new type. This is one of the options
> described in Opaque proposal (see The return type issue). Why the
> other alternatives have less sens?
>
>
> There are many differences between my proposal and the Opaque=20
> proposal. I believe that the main ones that this proposal brings are:
>
> - Where possible, do not introduce new meanings or rules to the=20
> language. The type-copied class should behave as closely as possible=20
> to a class the user has implemented by hand. This should make very=20
> easy to understand how the feature works, without the need to grasp=20
> many new concepts.
> - I have removed the option to modify and remove existing=20
> functionality from the class that is being copied. While I believe=20
> that this can be useful, it introduces too much complexity in my=20
> opinion now. If this is allowed, you basically have to create a system=20
> where you are allowed to completely rewrite an existing class starting=20
> from another, since you may want to copy or remove or change anything=20
> that was previously present. This I believe can both make the proposal=20
> unnecessary complicated, and can make the code very hard to follow, as=20
> at each new strong-typedef step (since a type could be copied, and the=20
> copy copied again and so on) anything could happen. I now believe that=20
> an incremental-only strategy (similar to inheritance) can still be=20
> both useful and sufficient for most cases. Where it is not, simple=20
> implementations by hand of basic functionality, extended then via the=20
> type-copy mechanism should result in clear, reusable code which still=20
> requires little maintenance.
To be honest, I will vote against this proposal if we can not modify and=20
delete existing functionality. When I copy/paste a class I can change=20
things and remove others.
>
> The word duplicating and wrapping don't match. The proposed
> approach doesn't wraps the underlying type, except maybe for
> builtin types.
>
>
> Right, I'll fix it, thanks.
>
> I believe the proposal needs to add some concrete examples as use
> cases
>
>
> This makes sense, I'll worn ok an additional section where I try to=20
> show some concrete examples.
The best will be to add them in the motivation section showing how the=20
new feature is used instead of some flat code.
>
> If the base class change, the strong types depending on it could
> need maintenance also, isn't it?
>
>
> True, however wrapper methods have to be fixed 100% of the time, while=20
> a type-copied class may not need this. It's the same as if one=20
> modified a base class in inheritance - you don't have to necessarily=20
> update all the code that depends on it right away.
One of the problems of your proposal is that the copied class has access=20
to the private members, which is more subject to changes. I believe that=20
the copied class should only have access to public members.
>
> In addition to these basic techniques, there are other library
> solution, as e.g. using CRTP that might merit to be mentioned.
> See [TBoost.Opaque] for a possible implementation.
>
>
> I'll add a mention to CRTP. I'll give a look at the boost link, thanks!
>
> Please add
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf>
> to this list.
>
>
> Thanks, I must have missed it.
>
> What is wrong for you with p0109r0 approach?
> What we could have with your approach that we cannot have with
> p0109r0?
> What we could have with p0109r0 that we cannot have with your
> approach?
>
> IIUC, p0109r0 opaque types don't introduce any operations by
> default other than conversions and your proposal introduce all
> members but no friends
>
>
> Personally, I don't think there's anything "wrong" with p0109r0. The=20
> idea for this proposal came to me before I knew the alternatives, but=20
> since C++ still does not have strong typedefs I thought I might as=20
> well propose an alternative approach, which could possibly garner more=20
> interest.
>
> I believe my approach is simpler to read and more intuitive -=20
> especially when creating strong aliases of very complex types, but=20
> that can definitely be bias. It can be applied to hierarchies of=20
> classes, since it allows type-copying interdependent classes, which I=20
> believe is very important. It is very easy to use with templates and=20
> specializations, which potentially gives it a lot of power and very=20
> many potential uses. It is easily composable, as in copying a copy is=20
> very easy and indeed expected in my view for the feature.
You will need to show how all this arguments applies on concrete=20
examples and how p0109r0 could do the same thing.
>
> With p0109r0 there's more flexibility to alter a type. The additional=20
> flexibility allows it to take on more tasks, as in type-copying=20
> friends, since default ways to convert to the original types exist. It=20
> is designed for primitive types first, while I have actually removed=20
> them in my last iteration for a number of reasons (see below).
Again, I will vote against this proposal if it doesn't provides a=20
solution for builtin types, as this is IMHO one of the most appealing=20
use cases.
> The additional flexibility however comes at a cost, as you mention the=20
> return type issue, which my proposal does not have.
Your proposal has already this issue as you copy the whole class, and so=20
you replace every occurrence of the base class with the new class.
>
> I don't introduce friends mostly because a feature to create=20
> type-aliases of methods does not currently exist,
I don't know what do you mean by type-aliases of methods. Could you=20
elaborate?
> and I don't believe it is wise to add it to the scope of this proposal=20
> since it would be another very large change. If such a feature=20
> existed, however, adding friends to a type-copied class in my proposal=20
> would be trivial, as simply strong typedefs of the needed functions=20
> could be created on the fly. The same could also be done for=20
> non-member functions if needed, but how that would work I have not=20
> thought about yet.
Could you elaborate how type-aliases of methods would help here?
>
> I find that conversions to/from the underlying type must be
> covered by the proposal. If we change the Base type we don't want
> to be forced to redefine the conversion operator.
> Maybe we need some kind of default conversion implementation
> operator Base() *=3D default*;
> or
> *explicit* operator Base() *=3D default*;
>
>
> I like this. I didn't add it to keep the number of features as low as=20
> reasonably possible, but this is simple enough. This could also be=20
> used recursively, as in a copy of a copy could define a conversion=20
> operator to both the first copy and the original in this way.
Could you elaborate?
> However, this default way to define a conversion operator would be=20
> disabled if the copy has added new attributes with respect to its=20
> original class.
Why?
>
> Why do you introduce this restriction? (on template parameter numbers=
)
>
>
> No actually, you're right. I should lift it. I thought initially that=20
> there wouldn't be any reason to add more template parameters, as they=20
> would only be needed to satisfy the original class. But this is=20
> definitely wrong. I'll change it, thanks.
>
> In ** above C has not yet defined as a copy
>
>
> Ill explain how I believe this example should work. Since C has been=20
> declared but not defined when parsing D, the compiler will be allowed=20
> to assume that C is going to be defined later as a type-copy of A. If=20
> that does not happen, then the compiler will give an error, either at=20
> the definition of C or of D, explaining that D assumed that C would=20
> have been a type-copy while it was not. If C has added new attributes=20
> to its declaration though D's definition would need to take the new=20
> size of C into account though. Not sure if this can be done or if it=20
> should result in an error.
I don't know compiler writers would like to look ahead. I believe that C=20
should be forward declared as a copy.
>
> I believe this interdependent case introduce a lot of complexity.
> We would need a good use case to introduce it on the standard.
>
>
> A very simple example would be copying of inherited classes, both base=20
> and derived. Without a way to do this that just cannot be done. This=20
> can be important if one does not want that the derived type and its=20
> type-copy are allowed to be converted to the same base. This is a=20
> strong reason, I believe, otherwise strong-typing in that case just=20
> lost some power in keeping original and type-copy apart.
I will need a concrete example of when a complete hierarchy must be=20
"duplicated". I'm not saying there are no cases, just I have no one in=20
my head.
>
> I believe that this cannot be optional as in a lot of cases we
> need to modify/restrict the base type interface.
>
>
> I have actually removed this in my newest revision. I believe that=20
> ground-up building of types is the better way to go (as is normally=20
> done in inheritance). Having the power to completely alter the=20
> original type, possibly to a point where there was not even much in=20
> common between the original and the type-copy, is not worth it. This=20
> is a personal opinion, but I believe doing so can prevent some very=20
> complex and ugly code smells, at a not incredible cost.
We need to solve concrete problems. The 1st use case I have for strongly=20
types is to reduce the interface provided by the underlying type and to=20
adapt the functions signatures to the new class.
>
> Could you give a concrete example of this kind of problems?
>
>
> Suppose
>
> struct A {
> int foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> struct B : using A {
> int foo(int) =3D delete;
> // bar cannot compile anymore
> };
>
Where is the problem? struct B will not compile. That's all.
> struct C : using A {
> double foo(int x) { return x * 2; }
> // ambiguous definition
> };
>
You are not modifying here, but adding ;-). You can say it is ambiguous,=20
but we have this case with inheritance=20
(http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl)
> struct D : using A {
> double foo(double x) { return x * 3; }
> // Changes meaning of bar underhandedly with no warning
> };
>
I don't see a problem here as D is a copy of A and then we are defining=20
its meaning.
You said that it should be as simple as if defined the class by hand.
> I suppose even more dangerous and complex cases could be devised.
We will need some real examples to see how dangerous they are ;-)
>
> While this is inline with your approach, this merits some
> explanations as the operators are no members. Shouldn't the
> operators of UDT classes meritt to be inherited as well?
>
>
> I've removed primitive type support also for this reason. They are not=20
> currently treated as classes by C++, and so I think I shouldn't=20
> either. Instead my approach is now constructive. If one needed aliases=20
> for primitive types, one could create a single header of wrappers in=20
> the form
>
> template <typename T>
> class SimpleWrapper {
> public:
> SimpleWrapper(T t) : t_(t) {}
>
> private:
> T t_;
> };
>
> template <typename T>
> struct SimpleWrapperWithSum : using SimpleWrapper<T> {
> SimpleWrapperWithSum operator+(const SimpleWrapperWithSum & other)=20
> { return t_ + other.t_; }
> };
>
> And so on. It would only be needed once, and then users could simply=20
> copy the versions with the operators they need to use. It's not=20
> incredibly pretty and it does have some limitations, but it works,
I believe it is worth mentioning it in the proposal. My TBoost.Opaque=20
library implements something like that. I will start a new thread to=20
talk about the TBoost.Opaque library approach. If I need a library=20
solution for builtin types, why this library solution will not work for=20
classes, what will be the added value of the language solution?
> and in any case even in p0109r0 one would need to remove all unneeded=20
> operators, so work would need to be done anyway.
No p0109r0 doesn't define any operation by default (except conversions).=20
The user needs to add whatever is needed, maybe using the default=20
trampoline implementation). Well this is how I understand it.
>
> I believed that there where no implicit conversions on your
> proposals. How (*this) is converted to an int?
>
> What would be the result type of x below?
>
> Id id(1);
> auto x =3D +id;
>
> I suspect that it would be Id.
>
> Yeah, this was a weird syntax, I thought it could be a simple way to=20
> represent conversion to the underlying primitive type.
>
> The type of the operation would be Id, yes. I believe that to be the=20
> only intuitive result that makes sense, unless an explicit operator+=20
> that does a conversion has been defined somewhere. If a cast is=20
> needed, one needs to cast. I don't see a reason to change that for=20
> strong typedefs, otherwise the language would be inconsistent IMO.
>
> Why this restriction is needed or desirable.(w.r.t. final in
> type-copies of primitive types)
>
>
> It is not. But I believe that if one needs to do something, it has to=20
> be in line with the rest of the language. If a strong typedef of a=20
> primitive type is needed, it would still need to follow the rules of=20
> primitive types.
It depends. If a strong type is able to define new members it is not=20
anymore a builtin and becomes for me a class.
> As primitive types are not inheritable, I believe neither should the=20
> strong typedefs. Maybe this is a wrong position, I don't know (since=20
> primitive typedefs are not inheritable due to C compatibilities IIUC),=20
> but I believe that having consistency is still useful for a proposal.=20
> Otherwise one needs to always learn a million exceptions to each rule,=20
> and that I don't like, where it can be avoided. In any case, these are=20
> my opinions, but if there is strong consensus to change how the=20
> proposal works I have no problem in modifying it.
You need to justify your decisions on a rationale section. But as you=20
have removed builtin types as base types this is not needed anymore. You=20
will need to justify why builtin are not supported :(
>
> Example of where this can be useful welcome.
>
>
> I must admit I didn't really think about this, I just thought they=20
> could be nice to have. Maybe they would be useless. I just considered=20
> that sometimes the ingenuity of how people use tools always seem to=20
> surprise, so why not. Maybe in order to SFINAE the generation of=20
> conversion operators to classes, given that they are copies of the=20
> original? Something like
>
> struct Copy : using A {
> template <typename T, /* enable_if_t<is_copy_of_v<T, A>>> */>
> operator T =3D default;
> };
Features must be added to solve concrete problems.
I suggest you to work on the motivation section with real concrete examples=
..
>
> How other type traits behave for the copied class (see p0109r0)?
>
>
> All other type traits behave as if the class had been implemented by=20
> hand, and is separate from the original. so is_same would return=20
> false, for example. It seems that p0109r0 thinks the same way. The=20
> only difference is that sizeof may be different, since in my proposal=20
> one could add additional attributes to the type-copied class. (There's=20
> no examples in the old version, I've added them on GitHub though).
I agree for is_same of course. I was wondering for other traits that=20
could have been specialized for the base class. I suspect the answer is=20
that the user would need to specialize the new type again.
>
> Thanks again for your feedback.
You are welcome,
Vicente
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.f=
r.
--------------52A047125D7EFF2D8235B50C
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 31/12/2016 =C3=A0 15:57, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Dear Vincente,<br>
<br>
</div>
Thank you for your very in-depth review. I've updated the
proposal using already received comments from this thread,
so some things have changed, but it's still alright to
receive comments on this version. I'll explain below how
it has changed when answering to your comments.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">IIUC, every
occurrence of the base type in the definition of the
base type is replaced by the new type. This is one of
the options described in Opaque proposal (see The return
type issue). Why the other alternatives have less sens?<spa=
n
class=3D"m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></blo=
ckquote>
<span class=3D"m_-5826156030849956333gmail-im"> </span><br>
</div>
There are many differences between my proposal and the
Opaque proposal. I believe that the main ones that this
proposal brings are:<br>
<br>
</div>
- Where possible, do not introduce new meanings or rules to
the language. The type-copied class should behave as closely
as possible to a class the user has implemented by hand. This
should make very easy to understand how the feature works,
without the need to grasp many new concepts.<br>
</div>
- I have removed the option to modify and remove existing
functionality from the class that is being copied. While I
believe that this can be useful, it introduces too much
complexity in my opinion now. If this is allowed, you basically
have to create a system where you are allowed to completely
rewrite an existing class starting from another, since you may
want to copy or remove or change anything that was previously
present. This I believe can both make the proposal unnecessary
complicated, and can make the code very hard to follow, as at
each new strong-typedef step (since a type could be copied, and
the copy copied again and so on) anything could happen. I now
believe that an incremental-only strategy (similar to
inheritance) can still be both useful and sufficient for most
cases. Where it is not, simple implementations by hand of basic
functionality, extended then via the type-copy mechanism should
result in clear, reusable code which still requires little
maintenance.<br>
</div>
</blockquote>
To be honest, I will vote against this proposal if we can not modify
and delete existing functionality. When I copy/paste a class I can
change things and remove others.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr"><br>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">The word duplicating
and wrapping don't match. The proposed approach doesn't
wraps the underlying type, except maybe for builtin
types.<br>
</blockquote>
<br>
</div>
<div>Right, I'll fix it, thanks.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I believe the
proposal needs to add some concrete examples as use
cases<br>
</blockquote>
</div>
<div><br>
</div>
<div>This makes sense, I'll worn ok an additional section
where I try to show some concrete examples.<br>
</div>
</div>
</div>
</div>
</blockquote>
The best will be to add them in the motivation section showing how
the new feature is used instead of some flat code.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">If the base class
change, the strong types depending on it could need
maintenance also, isn't it?<span
class=3D"m_-5826156030849956333gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True, however wrapper methods have to be fixed 100%
of the time, while a type-copied class may not need
this. It's the same as if one modified a base class in
inheritance - you don't have to necessarily update all
the code that depends on it right away.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
One of the problems of your proposal is that the copied class has
access to the private members, which is more subject to changes. I
believe that the copied class should only have access to public
members.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">In addition to
these basic techniques, there are other library
solution, as e.g. using CRTP that might merit to be
mentioned.<br>
See [TBoost.Opaque] for a possible implementation.<span
class=3D"m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></b=
lockquote>
<br>
</div>
<div>I'll add a mention to CRTP. I'll give a look at the
boost link, thanks!<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Please add <a
moz-do-not-send=3D"true"
class=3D"m_-5826156030849956333gmail-m_-7522649930861642754moz-txt-link-fre=
etext"
href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf=
"
target=3D"_blank">http://www.open-std.org/jtc1/s<wbr>c2=
2/wg21/docs/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span
class=3D"m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></b=
lockquote>
<br>
</div>
<div>Thanks, I must have missed it.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">What is wrong for
you with p0109r0 approach?<br>
What we could have with your approach that we cannot
have with p0109r0?<br>
What we could have with p0109r0 that we cannot have
with your approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce any
operations by default other than conversions and your
proposal introduce all members but no friends<span
class=3D"m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></b=
lockquote>
<br>
</div>
<div>Personally, I don't think there's anything "wrong"
with p0109r0. The idea for this proposal came to me
before I knew the alternatives, but since C++ still does
not have strong typedefs I thought I might as well
propose an alternative approach, which could possibly
garner more interest.<br>
<br>
</div>
<div>I believe my approach is simpler to read and more
intuitive - especially when creating strong aliases of
very complex types, but that can definitely be bias. It
can be applied to hierarchies of classes, since it
allows type-copying interdependent classes, which I
believe is very important. It is very easy to use with
templates and specializations, which potentially gives
it a lot of power and very many potential uses. It is
easily composable, as in copying a copy is very easy and
indeed expected in my view for the feature.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You will need to show how all this arguments applies on concrete
examples and how p0109r0 could do the same thing.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>With p0109r0 there's more flexibility to alter a
type. The additional flexibility allows it to take on
more tasks, as in type-copying friends, since default
ways to convert to the original types exist. It is
designed for primitive types first, while I have
actually removed them in my last iteration for a number
of reasons (see below). </div>
</div>
</div>
</div>
</div>
</blockquote>
Again, I will vote against this proposal if it doesn't provides a
solution for builtin types, as this is IMHO one of the most
appealing use cases.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The additional flexibility however comes at a cost,
as you mention the return type issue, which my proposal
does not have.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Your proposal has already this issue as you copy the whole class,
and so you replace every occurrence of the base class with the new
class.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>I don't introduce friends mostly because a feature to
create type-aliases of methods does not currently exist,
</div>
</div>
</div>
</div>
</div>
</blockquote>
I don't know what do you mean by type-aliases of methods. Could you
elaborate?<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>and I don't believe it is wise to add it to the scope
of this proposal since it would be another very large
change. If such a feature existed, however, adding
friends to a type-copied class in my proposal would be
trivial, as simply strong typedefs of the needed
functions could be created on the fly. The same could
also be done for non-member functions if needed, but how
that would work I have not thought about yet.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Could you elaborate how type-aliases of methods would help here?<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I find that
conversions to/from the underlying type must be
covered by the proposal. If we change the Base type we
don't want to be forced to redefine the conversion
operator.<br>
Maybe we need some kind of default conversion
implementation<br>
<span style=3D"font-family:courier new,monospace">=C2=A0=
=C2=A0=C2=A0
operator Base() <b>=3D default</b>;</span><br>
<span style=3D"font-family:courier new,monospace"> or </s=
pan><br>
<span style=3D"font-family:courier new,monospace">=C2=A0=
=C2=A0=C2=A0 <b>explicit</b>
operator Base() <b>=3D default</b>;</span><br>
</blockquote>
</div>
<div><br>
</div>
<div>I like this. I didn't add it to keep the number of
features as low as reasonably possible, but this is
simple enough. This could also be used recursively, as
in a copy of a copy could define a conversion operator
to both the first copy and the original in this way. </div>
</div>
</div>
</div>
</div>
</blockquote>
Could you elaborate?<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a conversion
operator would be disabled if the copy has added new
attributes with respect to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Why?<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Why do you
introduce this restriction? (on template parameter
numbers)<br>
</blockquote>
</div>
<div><br>
</div>
<div>No actually, you're right. I should lift it. I
thought initially that there wouldn't be any reason to
add more template parameters, as they would only be
needed to satisfy the original class. But this is
definitely wrong. I'll change it, thanks.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">In ** above C has
not yet defined as a copy<span
class=3D"m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></b=
lockquote>
<br>
</div>
<div>Ill explain how I believe this example should work.
Since C has been declared but not defined when parsing
D, the compiler will be allowed to assume that C is
going to be defined later as a type-copy of A. If that
does not happen, then the compiler will give an error,
either at the definition of C or of D, explaining that D
assumed that C would have been a type-copy while it was
not. If C has added new attributes to its declaration
though D's definition would need to take the new size of
C into account though. Not sure if this can be done or
if it should result in an error.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I don't know compiler writers would like to look ahead. I believe
that C should be forward declared as a copy.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I believe this
interdependent case introduce a lot of complexity. We
would need a good use case to introduce it on the
standard.<span class=3D"m_-5826156030849956333gmail-im"><=
/span><br>
<span class=3D"m_-5826156030849956333gmail-im"></span></b=
lockquote>
<br>
</div>
<div>A very simple example would be copying of inherited
classes, both base and derived. Without a way to do this
that just cannot be done. This can be important if one
does not want that the derived type and its type-copy
are allowed to be converted to the same base. This is a
strong reason, I believe, otherwise strong-typing in
that case just lost some power in keeping original and
type-copy apart.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I will need a concrete example of when a complete hierarchy must be
"duplicated". I'm not saying there are no cases, just I have no one
in my head.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I believe that this
cannot be optional as in a lot of cases we need to
modify/restrict the base type interface.<br>
</blockquote>
<br>
</div>
<div>I have actually removed this in my newest revision. I
believe that ground-up building of types is the better
way to go (as is normally done in inheritance). Having
the power to completely alter the original type,
possibly to a point where there was not even much in
common between the original and the type-copy, is not
worth it. This is a personal opinion, but I believe
doing so can prevent some very complex and ugly code
smells, at a not incredible cost.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
We need to solve concrete problems. The 1st use case I have for
strongly types is to reduce the interface provided by the underlying
type and to adapt the functions signatures to the new class.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>Could you give a concrete example of this kind of
problems?<br>
</div>
</blockquote>
<div>
<div style=3D"margin-left:40px"><span
class=3D"m_-5826156030849956333gmail-im"></span></div>
<br>
</div>
<div>Suppose<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; =
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return f=
oo(x) * 4.0; }<br>
};<br>
</div>
<div><br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int foo(int) =3D delete;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // bar cannot compile anymore<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Where is the problem? struct B will not compile. That's all.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct C : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(int x) { return x * 2; }<b=
r>
</div>
<div>=C2=A0=C2=A0=C2=A0 // ambiguous definition<br>
};<br>
</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You are not modifying here, but adding ;-). You can say it is
ambiguous, but we have this case with inheritance
(<a class=3D"moz-txt-link-freetext" href=3D"http://melpon.org/wandbox/p=
ermlink/f9mRtE9n5mA9RPpl">http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RP=
pl</a>)<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct D : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(double x) { return x * 3; =
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // Changes meaning of bar underhanded=
ly with no
warning<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I don't see a problem here as D is a copy of A and then we are
defining its meaning.<br>
You said that it should be as simple as if defined the class by
hand.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>I suppose even more dangerous and complex cases could
be devised.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
We will need some real examples to see how dangerous they are ;-)<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">While this is
inline with your approach, this merits some
explanations as the operators are no members.
Shouldn't the operators of UDT classes meritt to be
inherited as well?<br>
</blockquote>
<div><br>
</div>
<div>I've removed primitive type support also for this
reason. They are not currently treated as classes by
C++, and so I think I shouldn't either. Instead my
approach is now constructive. If one needed aliases
for primitive types, one could create a single header
of wrappers in the form<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>class SimpleWrapper {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 public:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 SimpleWrapp=
er(T t) : t_(t) {}<br>
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br>
</div>
<div>};<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>struct SimpleWrapperWithSum : using
SimpleWrapper<T> {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 SimpleWrapperWithSum operator+(cons=
t
SimpleWrapperWithSum & other) { return t_ +
other.t_; }<br>
</div>
<div>};<br>
<br>
</div>
<div>And so on. It would only be needed once, and then
users could simply copy the versions with the
operators they need to use. It's not incredibly pretty
and it does have some limitations, but it works, </div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I believe it is worth mentioning it in the proposal. My
TBoost.Opaque library implements something like that. I will start a
new thread to talk about the TBoost.Opaque library approach. If I
need a library solution for builtin types, why this library solution
will not work for classes, what will be the added value of the
language solution?<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>and in any case even in p0109r0 one would need to
remove all unneeded operators, so work would need to
be done anyway. <br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
No p0109r0 doesn't define any operation by default (except
conversions). The user needs to add whatever is needed, maybe using
the default trampoline implementation). Well this is how I
understand it.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>I believed that there where no implicit
conversions on your proposals. How (*this) is
converted to an int?<br>
<br>
What would be the result type of x below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span
class=3D"m_-5826156030849956333gmail-im"></span><br>
</div>
</blockquote>
<div>
<blockquote><span
class=3D"m_-5826156030849956333gmail-im"></span></blo=
ckquote>
Yeah, this was a weird syntax, I thought it could be a
simple way to represent conversion to the underlying
primitive type.<br>
<br>
The type of the operation would be Id, yes. I believe
that to be the only intuitive result that makes sense,
unless an explicit operator+ that does a conversion
has been defined somewhere. If a cast is needed, one
needs to cast. I don't see a reason to change that for
strong typedefs, otherwise the language would be
inconsistent IMO.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Why this
restriction is needed or desirable.<span
class=3D"m_-5826156030849956333gmail-im"> (w.r.t.
final in type-copies of primitive types)<br>
</span></blockquote>
<div><br>
</div>
<div>It is not. But I believe that if one needs to do
something, it has to be in line with the rest of the
language. If a strong typedef of a primitive type is
needed, it would still need to follow the rules of
primitive types. </div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
It depends. If a strong type is able to define new members it is not
anymore a builtin and becomes for me a class.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>As primitive types are not inheritable, I believe
neither should the strong typedefs. Maybe this is a
wrong position, I don't know (since primitive
typedefs are not inheritable due to C
compatibilities IIUC), but I believe that having
consistency is still useful for a proposal.
Otherwise one needs to always learn a million
exceptions to each rule, and that I don't like,
where it can be avoided. In any case, these are my
opinions, but if there is strong consensus to change
how the proposal works I have no problem in
modifying it.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You need to justify your decisions on a rationale section. But as
you have removed builtin types as base types this is not needed
anymore. You will need to justify why builtin are not supported :(=C2=
=A0
<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Example of
where this can be useful welcome.<br>
</blockquote>
<div><br>
</div>
<div>I must admit I didn't really think about this,
I just thought they could be nice to have. Maybe
they would be useless. I just considered that
sometimes the ingenuity of how people use tools
always seem to surprise, so why not. Maybe in
order to SFINAE the generation of conversion
operators to classes, given that they are copies
of the original? Something like<br>
<br>
</div>
<div>struct Copy : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 template <typename T, =
/*
enable_if_t<is_copy_of_v<T, A>>>
*/><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 operator T =3D default;<b=
r>
</div>
<div>};<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Features must be added to solve concrete problems.<br>
<br>
I suggest you to work on the motivation section with real concrete
examples.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">How other
type traits behave for the copied class (see
p0109r0)?<br>
</blockquote>
<br>
</div>
<div>All other type traits behave as if the class
had been implemented by hand, and is separate from
the original. so is_same would return false, for
example. It seems that p0109r0 thinks the same
way. The only difference is that sizeof may be
different, since in my proposal one could add
additional attributes to the type-copied class.
(There's no examples in the old version, I've
added them on GitHub though).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I agree for is_same of course. I was wondering for other traits that
could have been specialized for the base class. I suspect the answer
is that the user would need to specialize the new type again.<br>
<blockquote
cite=3D"mid:CAHfn=3D+t0MkFNY4h=3DcrQWvh=3DJT2nHt5k_LWnO=3DSzgGkL2Q=3D_bSw@m=
ail.gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Thanks again for your feedback.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You are welcome,<br>
Vicente<br>
<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-e5cf8b4ff3ca%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-e5cf8b4ff3ca=
%40wanadoo.fr</a>.<br />
--------------52A047125D7EFF2D8235B50C--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Sat, 31 Dec 2016 19:39:16 +0100
Raw View
--001a114dae72ca72e10544f8a227
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
>
> To be honest, I will vote against this proposal if we can not modify and
> delete existing functionality. When I copy/paste a class I can change
> things and remove others.
>
I really understand this feeling. However, consider this: at which point is
something a strong typedef of something else, and when is it a new class?
Is the mechanism we want to introduce simply a way to declare a new class,
using another as a starting point and completely editable, or we want there
to be some kind of association (even if it was only on a logical level)
between the two things?
A mechanism that freely allows you to edit classes wouldn't be a strong
typedef, in my opinion. Consider:
struct A {
void foo();
};
struct B : using A {
void foo() =3D delete;
void bar();
};
Why would you have copied A in the first place then, rather than create a
new class? If instead you could say "copies can only add" then when you
find a class declared as a copy you can easily reason about it. Think about
a long chains of copies:
struct A { /* .... */ };
struct B : using A { /* .... */ };
struct C : using B { /* .... */ };
struct D : using C { /* .... */ };
struct E : using D { /* .... */ };
All these maybe in different files, in different places. Then what is E? If
you are allowed to remove and change things, then you'd have to start at A
and manually keep track of which things are deleted, maybe re-added later,
maybe modified. It would be really hard to know exactly what E is. While if
you're allowed to only increment, it would be much easier to know that - or
at least on par with inheritance. If you can find it once in the chain,
then it exists. I believe this is an important fact that must be considered
when thinking about what features we want in strong typing.
One of the problems of your proposal is that the copied class has access to
> the private members, which is more subject to changes. I believe that the
> copied class should only have access to public members.
If one creates a new class, and private members cannot be accessed, there
will not be any way to touch them to do anything else aside from the
original interface. This is also compounded by the fact that all old
methods accepting the original class won't work on the new class (creating
an operator Base() should be an exception for certain use-cases, it should
not be necessary to do so). How are you going to print a copy? How can you
convert in a custom way to the original class? How are you going to
implement additional and useful methods without access to privates?
Again, I will vote against this proposal if it doesn't provides a solution
> for builtin types, as this is IMHO one of the most appealing use cases.
>
A solution exists, and is the one that already exists when one wants to
limit operations done on existing types: build a wrapper. The difference is
that before a completely new wrapper had to be built from scratch for each
new needed primitive alias, depending on the required operations, with this
proposal they become easily composable, so once done it never has to be
done again, and adding new types becomes a one-liner for the user.
Consider this against what p0109r0 does:
template <class T =3D double>
using energy =3D protected double {
energy operator+ (energy , energy) =3D default;
energy& operator*=3D(energy&, T ) =3D default;
energy operator*(energy , energy) =3D delete;
energy operator*(energy , T ) =3D default;
energy operator*(T , energy) =3D default;
};
You see that in order to have a custom type, still many things must be
written. So what's the difference between creating copyable wrappers (using
normal C++ rules), and creating a number of such interfaces (having to
learn and teach how protected/public/private work in a new context)? I
don't see what the difference would be. Why do you feel that wrappers on
primitive types are not enough?
Your proposal has already this issue as you copy the whole class, and so
> you replace every occurrence of the base class with the new class.
>
I'm not sure what you mean. In my proposal, the copy is a new class, and so
it is always obvious what an assignment operator is going to result in. In
p0109r0 this is more complex because depending on the access specifier
different default conversion operators are defined. Not sure what you mean
when you mention the replacement that happens, and what the issue is.
I don't know what do you mean by type-aliases of methods. Could you
> elaborate?
>
Yes. So consider this:
struct A {
friend void foo(A&);
};
struct B : using A {};
To me the only way to allow B to also have the friend declaration is if we
could do the following transformation:
void foo(A&) ----> void foo(B&)
In some sense creating a new foo overload using the type-copy. However, I
believe this would be a pretty big change. If such a thing was allowed,
then why stop at copies? Why not being able to define
void foo(A&) ----> void foo(C&)
or even
void foo(A&) ----> template<typename T> void foo(T&);
As this is outside of the scope of my proposal, I did not include this. And
so, I cannot add to my proposal the conversion of friend and non-member
function when creating a copy-type. If this could be included, there would
be no problem for that.
Could you elaborate? (on recursive conversion operator)
>
For example, consider
struct A {};
struct B : using A {
operator A() =3D default;
};
struct C : using B {
operator B() =3D default;
operator A() =3D default;
};
Just an idea.
However, this default way to define a conversion operator would be disabled
> if the copy has added new attributes with respect to its original class.
>
> Why?
>
I think that at that point the two classes diverged enough that the
compiler cannot assume they can be converted freely? If I have:
struct A { int x; };
struct B : using A { int y; };
Is it really wise to allow the compiler to be able to default convert B to
A? If they were the same, ok, but maybe at that point the user should be
forced to provide a conversion operator, no?
I don't know compiler writers would like to look ahead. I believe that C
> should be forward declared as a copy.
>
Maybe. I thought that inherited classes are also declared without
mentioning that they inherit, so I though that the same should hold for
copies.
I will need a concrete example of when a complete hierarchy must be
> "duplicated". I'm not saying there are no cases, just I have no one in my
> head.
>
I'll try to add these on the concrete examples.
You are not modifying here, but adding ;-). You can say it is ambiguous,
> but we have this case with inheritance (http://melpon.org/wandbox/
> permlink/f9mRtE9n5mA9RPpl)
>
Not quite, the resulting copied class would be equivalent to
struct C {
int foo(int x) { return x * 2; }
double foo(int x) { return x * 2; }
double bar(double x) { return foo(x) * 4.0; }
};
which is illegal, since you cannot overload on return type. Keep in mind
that there is no "layer" between the original class and what gets added to
the copy.
I don't see a problem here as D is a copy of A and then we are defining its
> meaning.
> You said that it should be as simple as if defined the class by hand.
>
That's true, and that's mostly what I don't like about giving the ability
to modify copied existing methods. It is definitely non-obvious that this
is happening. If you make a mistake, it will take a long time to figure out
that you involuntarily modified the behavior of the original class. That's
bad in my book.
I believe it is worth mentioning it in the proposal. My TBoost.Opaque
> library implements something like that. I will start a new thread to talk
> about the TBoost.Opaque library approach. If I need a library solution fo=
r
> builtin types, why this library solution will not work for classes, what
> will be the added value of the language solution?
>
I believe that wrapper types are just as good as primitive types. This is
also how it's always been in C++. The main problem was simply that doing
this over and over and over was incredibly unwieldy. I don't believe that
the reason why the older, in-C++ approaches didn't work is that they were
creating wrappers rather than "primitive type aliases". This proposal
eliminates the need for repetition as once done, it is done forever. A
library like boost can pre-produce often used primitive types wrappers once
in a single header, and be done forever.
No p0109r0 doesn't define any operation by default (except conversions).
> The user needs to add whatever is needed, maybe using the default
> trampoline implementation). Well this is how I understand it.
>
From the proposal: "Since all member functions of the underlying type are
known to the compiler, we can take advantage of this and therefore propose
that the compiler, by default, generate default versions of these
trampolines."
Features must be added to solve concrete problems.
>
> I suggest you to work on the motivation section with real concrete
> examples.
>
Yes, I'll work on those, promise! ;)
On Sat, Dec 31, 2016 at 6:15 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit :
>
> Dear Vincente,
>
> Thank you for your very in-depth review. I've updated the proposal using
> already received comments from this thread, so some things have changed,
> but it's still alright to receive comments on this version. I'll explain
> below how it has changed when answering to your comments.
>
> IIUC, every occurrence of the base type in the definition of the base typ=
e
>> is replaced by the new type. This is one of the options described in Opa=
que
>> proposal (see The return type issue). Why the other alternatives have le=
ss
>> sens?
>>
>
> There are many differences between my proposal and the Opaque proposal. I
> believe that the main ones that this proposal brings are:
>
> - Where possible, do not introduce new meanings or rules to the language.
> The type-copied class should behave as closely as possible to a class the
> user has implemented by hand. This should make very easy to understand ho=
w
> the feature works, without the need to grasp many new concepts.
> - I have removed the option to modify and remove existing functionality
> from the class that is being copied. While I believe that this can be
> useful, it introduces too much complexity in my opinion now. If this is
> allowed, you basically have to create a system where you are allowed to
> completely rewrite an existing class starting from another, since you may
> want to copy or remove or change anything that was previously present. Th=
is
> I believe can both make the proposal unnecessary complicated, and can mak=
e
> the code very hard to follow, as at each new strong-typedef step (since a
> type could be copied, and the copy copied again and so on) anything could
> happen. I now believe that an incremental-only strategy (similar to
> inheritance) can still be both useful and sufficient for most cases. Wher=
e
> it is not, simple implementations by hand of basic functionality, extende=
d
> then via the type-copy mechanism should result in clear, reusable code
> which still requires little maintenance.
>
> To be honest, I will vote against this proposal if we can not modify and
> delete existing functionality. When I copy/paste a class I can change
> things and remove others.
>
>
> The word duplicating and wrapping don't match. The proposed approach
>> doesn't wraps the underlying type, except maybe for builtin types.
>>
>
> Right, I'll fix it, thanks.
>
> I believe the proposal needs to add some concrete examples as use cases
>>
>
> This makes sense, I'll worn ok an additional section where I try to show
> some concrete examples.
>
> The best will be to add them in the motivation section showing how the ne=
w
> feature is used instead of some flat code.
>
>
> If the base class change, the strong types depending on it could need
>> maintenance also, isn't it?
>>
>
> True, however wrapper methods have to be fixed 100% of the time, while a
> type-copied class may not need this. It's the same as if one modified a
> base class in inheritance - you don't have to necessarily update all the
> code that depends on it right away.
>
> One of the problems of your proposal is that the copied class has access
> to the private members, which is more subject to changes. I believe that
> the copied class should only have access to public members.
>
>
> In addition to these basic techniques, there are other library solution,
>> as e.g. using CRTP that might merit to be mentioned.
>> See [TBoost.Opaque] for a possible implementation.
>>
>
> I'll add a mention to CRTP. I'll give a look at the boost link, thanks!
>
> Please add http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p010
>> 9r0.pdf to this list.
>>
>
> Thanks, I must have missed it.
>
> What is wrong for you with p0109r0 approach?
>> What we could have with your approach that we cannot have with p0109r0?
>> What we could have with p0109r0 that we cannot have with your approach?
>>
>> IIUC, p0109r0 opaque types don't introduce any operations by default
>> other than conversions and your proposal introduce all members but no
>> friends
>>
>
> Personally, I don't think there's anything "wrong" with p0109r0. The idea
> for this proposal came to me before I knew the alternatives, but since C+=
+
> still does not have strong typedefs I thought I might as well propose an
> alternative approach, which could possibly garner more interest.
>
> I believe my approach is simpler to read and more intuitive - especially
> when creating strong aliases of very complex types, but that can definite=
ly
> be bias. It can be applied to hierarchies of classes, since it allows
> type-copying interdependent classes, which I believe is very important. I=
t
> is very easy to use with templates and specializations, which potentially
> gives it a lot of power and very many potential uses. It is easily
> composable, as in copying a copy is very easy and indeed expected in my
> view for the feature.
>
> You will need to show how all this arguments applies on concrete examples
> and how p0109r0 could do the same thing.
>
>
> With p0109r0 there's more flexibility to alter a type. The additional
> flexibility allows it to take on more tasks, as in type-copying friends,
> since default ways to convert to the original types exist. It is designed
> for primitive types first, while I have actually removed them in my last
> iteration for a number of reasons (see below).
>
> Again, I will vote against this proposal if it doesn't provides a solutio=
n
> for builtin types, as this is IMHO one of the most appealing use cases.
>
> The additional flexibility however comes at a cost, as you mention the
> return type issue, which my proposal does not have.
>
> Your proposal has already this issue as you copy the whole class, and so
> you replace every occurrence of the base class with the new class.
>
>
> I don't introduce friends mostly because a feature to create type-aliases
> of methods does not currently exist,
>
> I don't know what do you mean by type-aliases of methods. Could you
> elaborate?
>
> and I don't believe it is wise to add it to the scope of this proposal
> since it would be another very large change. If such a feature existed,
> however, adding friends to a type-copied class in my proposal would be
> trivial, as simply strong typedefs of the needed functions could be creat=
ed
> on the fly. The same could also be done for non-member functions if neede=
d,
> but how that would work I have not thought about yet.
>
> Could you elaborate how type-aliases of methods would help here?
>
>
> I find that conversions to/from the underlying type must be covered by th=
e
>> proposal. If we change the Base type we don't want to be forced to redef=
ine
>> the conversion operator.
>> Maybe we need some kind of default conversion implementation
>> operator Base() *=3D default*;
>> or
>> *explicit* operator Base() *=3D default*;
>>
>
> I like this. I didn't add it to keep the number of features as low as
> reasonably possible, but this is simple enough. This could also be used
> recursively, as in a copy of a copy could define a conversion operator to
> both the first copy and the original in this way.
>
> Could you elaborate?
>
> However, this default way to define a conversion operator would be
> disabled if the copy has added new attributes with respect to its origina=
l
> class.
>
> Why?
>
>
> Why do you introduce this restriction? (on template parameter numbers)
>>
>
> No actually, you're right. I should lift it. I thought initially that
> there wouldn't be any reason to add more template parameters, as they wou=
ld
> only be needed to satisfy the original class. But this is definitely wron=
g.
> I'll change it, thanks.
>
> In ** above C has not yet defined as a copy
>>
>
> Ill explain how I believe this example should work. Since C has been
> declared but not defined when parsing D, the compiler will be allowed to
> assume that C is going to be defined later as a type-copy of A. If that
> does not happen, then the compiler will give an error, either at the
> definition of C or of D, explaining that D assumed that C would have been=
a
> type-copy while it was not. If C has added new attributes to its
> declaration though D's definition would need to take the new size of C in=
to
> account though. Not sure if this can be done or if it should result in an
> error.
>
> I don't know compiler writers would like to look ahead. I believe that C
> should be forward declared as a copy.
>
>
> I believe this interdependent case introduce a lot of complexity. We woul=
d
>> need a good use case to introduce it on the standard.
>>
>
> A very simple example would be copying of inherited classes, both base an=
d
> derived. Without a way to do this that just cannot be done. This can be
> important if one does not want that the derived type and its type-copy ar=
e
> allowed to be converted to the same base. This is a strong reason, I
> believe, otherwise strong-typing in that case just lost some power in
> keeping original and type-copy apart.
>
> I will need a concrete example of when a complete hierarchy must be
> "duplicated". I'm not saying there are no cases, just I have no one in my
> head.
>
>
> I believe that this cannot be optional as in a lot of cases we need to
>> modify/restrict the base type interface.
>>
>
> I have actually removed this in my newest revision. I believe that
> ground-up building of types is the better way to go (as is normally done =
in
> inheritance). Having the power to completely alter the original type,
> possibly to a point where there was not even much in common between the
> original and the type-copy, is not worth it. This is a personal opinion,
> but I believe doing so can prevent some very complex and ugly code smells=
,
> at a not incredible cost.
>
> We need to solve concrete problems. The 1st use case I have for strongly
> types is to reduce the interface provided by the underlying type and to
> adapt the functions signatures to the new class.
>
>
> Could you give a concrete example of this kind of problems?
>>
>
> Suppose
>
> struct A {
> int foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> struct B : using A {
> int foo(int) =3D delete;
> // bar cannot compile anymore
> };
>
> Where is the problem? struct B will not compile. That's all.
>
> struct C : using A {
> double foo(int x) { return x * 2; }
> // ambiguous definition
> };
>
> You are not modifying here, but adding ;-). You can say it is ambiguous,
> but we have this case with inheritance (http://melpon.org/wandbox/
> permlink/f9mRtE9n5mA9RPpl)
>
> struct D : using A {
> double foo(double x) { return x * 3; }
> // Changes meaning of bar underhandedly with no warning
> };
>
> I don't see a problem here as D is a copy of A and then we are defining
> its meaning.
> You said that it should be as simple as if defined the class by hand.
>
> I suppose even more dangerous and complex cases could be devised.
>
> We will need some real examples to see how dangerous they are ;-)
>
>
> While this is inline with your approach, this merits some explanations as
>> the operators are no members. Shouldn't the operators of UDT classes mer=
itt
>> to be inherited as well?
>>
>
> I've removed primitive type support also for this reason. They are not
> currently treated as classes by C++, and so I think I shouldn't either.
> Instead my approach is now constructive. If one needed aliases for
> primitive types, one could create a single header of wrappers in the form
>
> template <typename T>
> class SimpleWrapper {
> public:
> SimpleWrapper(T t) : t_(t) {}
>
> private:
> T t_;
> };
>
> template <typename T>
> struct SimpleWrapperWithSum : using SimpleWrapper<T> {
> SimpleWrapperWithSum operator+(const SimpleWrapperWithSum & other) {
> return t_ + other.t_; }
> };
>
> And so on. It would only be needed once, and then users could simply copy
> the versions with the operators they need to use. It's not incredibly
> pretty and it does have some limitations, but it works,
>
> I believe it is worth mentioning it in the proposal. My TBoost.Opaque
> library implements something like that. I will start a new thread to talk
> about the TBoost.Opaque library approach. If I need a library solution fo=
r
> builtin types, why this library solution will not work for classes, what
> will be the added value of the language solution?
>
> and in any case even in p0109r0 one would need to remove all unneeded
> operators, so work would need to be done anyway.
>
> No p0109r0 doesn't define any operation by default (except conversions).
> The user needs to add whatever is needed, maybe using the default
> trampoline implementation). Well this is how I understand it.
>
>
> I believed that there where no implicit conversions on your proposals. Ho=
w
>> (*this) is converted to an int?
>>
>> What would be the result type of x below?
>>
>> Id id(1);
>> auto x =3D +id;
>>
>> I suspect that it would be Id.
>>
> Yeah, this was a weird syntax, I thought it could be a simple way to
> represent conversion to the underlying primitive type.
>
> The type of the operation would be Id, yes. I believe that to be the only
> intuitive result that makes sense, unless an explicit operator+ that does=
a
> conversion has been defined somewhere. If a cast is needed, one needs to
> cast. I don't see a reason to change that for strong typedefs, otherwise
> the language would be inconsistent IMO.
>
> Why this restriction is needed or desirable. (w.r.t. final in type-copies
>> of primitive types)
>>
>
> It is not. But I believe that if one needs to do something, it has to be
> in line with the rest of the language. If a strong typedef of a primitive
> type is needed, it would still need to follow the rules of primitive type=
s.
>
> It depends. If a strong type is able to define new members it is not
> anymore a builtin and becomes for me a class.
>
> As primitive types are not inheritable, I believe neither should the
> strong typedefs. Maybe this is a wrong position, I don't know (since
> primitive typedefs are not inheritable due to C compatibilities IIUC), bu=
t
> I believe that having consistency is still useful for a proposal. Otherwi=
se
> one needs to always learn a million exceptions to each rule, and that I
> don't like, where it can be avoided. In any case, these are my opinions,
> but if there is strong consensus to change how the proposal works I have =
no
> problem in modifying it.
>
> You need to justify your decisions on a rationale section. But as you hav=
e
> removed builtin types as base types this is not needed anymore. You will
> need to justify why builtin are not supported :(
>
>
> Example of where this can be useful welcome.
>>
>
> I must admit I didn't really think about this, I just thought they could
> be nice to have. Maybe they would be useless. I just considered that
> sometimes the ingenuity of how people use tools always seem to surprise, =
so
> why not. Maybe in order to SFINAE the generation of conversion operators =
to
> classes, given that they are copies of the original? Something like
>
> struct Copy : using A {
> template <typename T, /* enable_if_t<is_copy_of_v<T, A>>> */>
> operator T =3D default;
> };
>
> Features must be added to solve concrete problems.
>
> I suggest you to work on the motivation section with real concrete
> examples.
>
>
> How other type traits behave for the copied class (see p0109r0)?
>>
>
> All other type traits behave as if the class had been implemented by hand=
,
> and is separate from the original. so is_same would return false, for
> example. It seems that p0109r0 thinks the same way. The only difference i=
s
> that sizeof may be different, since in my proposal one could add addition=
al
> attributes to the type-copied class. (There's no examples in the old
> version, I've added them on GitHub though).
>
> I agree for is_same of course. I was wondering for other traits that coul=
d
> have been specialized for the base class. I suspect the answer is that th=
e
> user would need to specialize the new type again.
>
>
> Thanks again for your feedback.
>
> You are welcome,
> Vicente
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-
> 51f2-e5cf8b4ff3ca%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a57116-c6=
5b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BtVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkR=
gGyWzZMgg%40mail.gmail.com.
--001a114dae72ca72e10544f8a227
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">To be ho=
nest, I will vote against this proposal if we can not modify
and delete existing functionality. When I copy/paste a class I can
change things and remove others.<span class=3D"gmail-im"></span><br></b=
lockquote><div><br></div><div>I really understand this feeling. However, co=
nsider this: at which point is something a strong typedef of something else=
, and when is it a new class? Is the mechanism we want to introduce simply =
a way to declare a new class, using another as a starting point and complet=
ely editable, or we want there to be some kind of association (even if it w=
as only on a logical level) between the two things?<br><br></div><div>A mec=
hanism that freely allows you to edit classes wouldn't be a strong type=
def, in my opinion. Consider:<br><br></div><div>struct A {<br></div><div>=
=C2=A0=C2=A0=C2=A0=C2=A0 void foo();<br>};<br><br></div><div>struct B : usi=
ng A {<br></div><div>=C2=A0=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br></d=
iv><div>=C2=A0=C2=A0=C2=A0=C2=A0 void bar();<br>};<br><br></div><div>Why wo=
uld you have copied A in the first place then, rather than create a new cla=
ss? If instead you could say "copies can only add" then when you =
find a class declared as a copy you can easily reason about it. Think about=
a long chains of copies:<br><br></div><div>struct A { /* .... */ };<br>str=
uct B : using A { /* .... */ };<br>struct C : using B { /* .... */ };<br>st=
ruct D : using C { /* .... */ };<br>struct E : using D { /* .... */ };<br><=
br></div><div>All these maybe in different files, in different places. Then=
what is E? If you are allowed to remove and change things, then you'd =
have to start at A and manually keep track of which things are deleted, may=
be re-added later, maybe modified. It would be really hard to know exactly =
what E is. While if you're allowed to only increment, it would be much =
easier to know that - or at least on par with inheritance. If you can find =
it once in the chain, then it exists. I believe this is an important fact t=
hat must be considered when thinking about what features we want in strong =
typing.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0p=
x 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One of the=
problems of your proposal is that the copied class has
access to the private members, which is more subject to changes. I
believe that the copied class should only have access to public
members.</blockquote><div><br></div>If one creates a new class, and pri=
vate members cannot be accessed, there will not be any way to touch them to=
do anything else aside from the original interface. This is also compounde=
d by the fact that all old methods accepting the original class won't w=
ork on the new class (creating an operator Base() should be an exception fo=
r certain use-cases, it should not be necessary to do so). How are you goin=
g to print a copy? How can you convert in a custom way to the original clas=
s? How are you going to implement additional and useful methods without acc=
ess to privates?<br><span class=3D"gmail-im"></span><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex">Again, I will vote against this proposal i=
f it doesn't provides a
solution for builtin types, as this is IMHO one of the most
appealing use cases.<span class=3D"gmail-im"></span><br><span class=3D"=
gmail-im"></span></blockquote><br></div><div>A solution exists, and is the =
one that already exists when one wants to limit operations done on existing=
types: build a wrapper. The difference is that before a completely new wra=
pper had to be built from scratch for each new needed primitive alias, depe=
nding on the required operations, with this proposal they become easily com=
posable, so once done it never has to be done again, and adding new types b=
ecomes a one-liner for the user.<br><br></div><div>Consider this against wh=
at p0109r0 does:<br><br><div style=3D"left: 153.208px; top: 609.361px; tran=
sform: scaleX(0.99626);"><font size=3D"2"><span style=3D"font-family:arial,=
helvetica,sans-serif">template <class T =3D double></span></font></di=
v><div style=3D"left: 153.208px; top: 629.286px; transform: scaleX(0.99626)=
;"><font size=3D"2"><span style=3D"font-family:arial,helvetica,sans-serif">=
using energy =3D protected double {</span></font></div><div style=3D"left: =
173.135px; top: 649.211px; transform: scaleX(0.99626);"><font size=3D"2"><s=
pan style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=A0=C2=A0 ene=
rgy operator+ (energy , energy) =3D default;</span></font></div><div style=
=3D"left: 342.502px; top: 669.136px; transform: scaleX(0.99626);"><font siz=
e=3D"2"><span style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=A0=
=C2=A0 energy& operator*=3D(energy&, T ) =3D default;</span></f=
ont></div><div style=3D"left: 352.463px; top: 689.062px; transform: scaleX(=
0.99626);"><font size=3D"2"><span style=3D"font-family:arial,helvetica,sans=
-serif">=C2=A0=C2=A0=C2=A0 energy operator*(energy , energy) =3D delete;</=
span></font></div><div style=3D"left: 352.463px; top: 708.987px; transform:=
scaleX(0.99626);"><font size=3D"2"><span style=3D"font-family:arial,helvet=
ica,sans-serif">=C2=A0=C2=A0=C2=A0 energy operator*(energy , T ) =3D d=
efault;</span></font></div><div style=3D"left: 352.463px; top: 728.912px; t=
ransform: scaleX(0.99626);"><font size=3D"2"><span style=3D"font-family:ari=
al,helvetica,sans-serif">=C2=A0=C2=A0=C2=A0 energy operator*(T , ener=
gy) =3D default;</span></font></div><div style=3D"left: 153.208px; top: 748=
..837px; transform: scaleX(0.99626);"><font size=3D"2"><span style=3D"font-f=
amily:arial,helvetica,sans-serif">};</span></font></div><br></div><div>You =
see that in order to have a custom type, still many things must be written.=
So what's the difference between creating copyable wrappers (using nor=
mal C++ rules), and creating a number of such interfaces (having to learn a=
nd teach how protected/public/private work in a new context)? I don't s=
ee what the difference would be. Why do you feel that wrappers on primitive=
types are not enough?<br><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex">Your proposal has already this issue as you copy the whole class,
and so you replace every occurrence of the base class with the new
class.<span class=3D"gmail-im"><br></span></blockquote><div><br></div><=
div>I'm not sure what you mean. In my proposal, the copy is a new class=
, and so it is always obvious what an assignment operator is going to resul=
t in. In p0109r0 this is more complex because depending on the access speci=
fier different default conversion operators are defined. Not sure what you =
mean when you mention the replacement that happens, and what the issue is.<=
br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex">I don't know w=
hat do you mean by type-aliases of methods. Could you
elaborate?<span class=3D"gmail-im"><br></span></blockquote><div><br></d=
iv><div>Yes. So consider this:<br><br></div><div>struct A {<br></div><div>=
=C2=A0 =C2=A0 friend void foo(A&);<br>};<br><br></div>struct B : using =
A {};<br><br></div><div>To me the only way to allow B to also have the frie=
nd declaration is if we could do the following transformation:<br><br></div=
><div>void foo(A&) ----> void foo(B&)<br><br></div><div>In some =
sense creating a new foo overload using the type-copy. However, I believe t=
his would be a pretty big change. If such a thing was allowed, then why sto=
p at copies? Why not being able to define<br><br></div><div>void foo(A&=
) ----> void foo(C&)<br><br></div><div>or even<br><br></div><div>voi=
d foo(A&) ----> template<typename T> void foo(T&);<br><br>=
</div><div>As this is outside of the scope of my proposal, I did not includ=
e this. And so, I cannot add to my proposal the conversion of friend and no=
n-member function when creating a copy-type. If this could be included, the=
re would be no problem for that.<br><br><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);pad=
ding-left:1ex">Could you elaborate? (on recursive conversion operator)<span=
class=3D"gmail-im"><br></span></blockquote><div><br></div><div>For example=
, consider<br><br></div><div>struct A {};<br></div><div>struct B : using A =
{<br></div><div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br></div><div>=
};<br></div><div>struct C : using B {<br></div><div>=C2=A0=C2=A0=C2=A0 oper=
ator B() =3D default;<br></div><div>=C2=A0=C2=A0=C2=A0 operator A() =3D def=
ault;<br>};<br><br></div><div>Just an idea.<br><br><blockquote class=3D"gma=
il_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,2=
04,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite=
">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a conversion
operator would be disabled if the copy has added new
attributes with respect to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Why?<span class=3D"gmail-im"><br></span></blockquote><div><br></div><di=
v>I think that at that point the two classes diverged enough that the compi=
ler cannot assume they can be converted freely? If I have:<br><br></div><di=
v>struct A { int x; };<br></div><div>struct B : using A { int y; };<br><br>=
</div><div>Is it really wise to allow the compiler to be able to default co=
nvert B to A? If they were the same, ok, but maybe at that point the user s=
hould be forced to provide a conversion operator, no?<br><br><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid=
rgb(204,204,204);padding-left:1ex">I don't know compiler writers would=
like to look ahead. I believe
that C should be forward declared as a copy.<span class=3D"gmail-im"><b=
r></span></blockquote><br></div><div>Maybe. I thought that inherited classe=
s are also declared without mentioning that they inherit, so I though that =
the same should hold for copies.<br></div><div><br><blockquote class=3D"gma=
il_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,2=
04,204);padding-left:1ex">I will need a concrete example of when a complete=
hierarchy must be
"duplicated". I'm not saying there are no cases, just I h=
ave no one
in my head.<span class=3D"gmail-im"></span><br><span class=3D"gmail-im"=
></span></blockquote><br></div><div>I'll try to add these on the concre=
te examples.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0=
px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">You a=
re not modifying here, but adding ;-). You can say it is
ambiguous, but we have this case with inheritance
(<a class=3D"gmail-m_2667955782052143795moz-txt-link-freetext" href=3D"=
http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl" target=3D"_blank">http=
://melpon.org/wandbox/<wbr>permlink/f9mRtE9n5mA9RPpl</a>)<span class=3D"gma=
il-im"></span><br><span class=3D"gmail-im"></span></blockquote><br></div><d=
iv>Not quite, the resulting copied class would be equivalent to<br><br></di=
v><div><div>struct C {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; =
}<br><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0=C2=A0 double foo(int x) { =
return x * 2; }</span><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return f=
oo(x) * 4.0; }<br>
};<br><br></div><div>which is illegal, since you cannot ove=
rload on return type. Keep in mind that there is no "layer" betwe=
en the original class and what gets added to the copy.<br><br><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px soli=
d rgb(204,204,204);padding-left:1ex">I don't see a problem here as D is=
a copy of A and then we are
defining its meaning.<br>
You said that it should be as simple as if defined the class by
hand.<span class=3D"gmail-im"></span><br><span class=3D"gmail-im"></spa=
n></blockquote><br></div><div>That's true, and that's mostly what I=
don't like about giving the ability to modify copied existing methods.=
It is definitely non-obvious that this is happening. If you make a mistake=
, it will take a long time to figure out that you involuntarily modified th=
e behavior of the original class. That's bad in my book.<br><br><blockq=
uote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1p=
x solid rgb(204,204,204);padding-left:1ex">I believe it is worth mentioning=
it in the proposal. My
TBoost.Opaque library implements something like that. I will start a
new thread to talk about the TBoost.Opaque library approach. If I
need a library solution for builtin types, why this library solution
will not work for classes, what will be the added value of the
language solution?<span class=3D"gmail-im"></span><br><span class=3D"gm=
ail-im"></span></blockquote><br></div><div>I believe that wrapper types are=
just as good as primitive types. This is also how it's always been in =
C++. The main problem was simply that doing this over and over and over was=
incredibly unwieldy. I don't believe that the reason why the older, in=
-C++ approaches didn't work is that they were creating wrappers rather =
than "primitive type aliases". This proposal eliminates the need =
for repetition as once done, it is done forever. A library like boost can p=
re-produce often used primitive types wrappers once in a single header, and=
be done forever.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">=
No p0109r0 doesn't define any operation by default (except
conversions). The user needs to add whatever is needed, maybe using
the default trampoline implementation). Well this is how I
understand it.<span class=3D"gmail-im"></span><br><span class=3D"gmail-=
im"></span></blockquote><br></div><div>From the proposal: "<span style=
=3D"font-family:arial,helvetica,sans-serif"><font size=3D"2">Since all memb=
er functions of the underlying type are known to the compiler, we can take =
advantage of this and therefore propose that the compiler, </font></span><s=
pan style=3D"font-family:arial,helvetica,sans-serif"><font size=3D"2">by de=
fault, generate default versions of these trampolines."<br><br></font>=
</span><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex">Features must be a=
dded to solve concrete problems.<br>
<br>
I suggest you to work on the motivation section with real concrete
examples.<span class=3D"gmail-im"></span><br><span class=3D"gmail-im"><=
/span></blockquote><br></div><div>Yes, I'll work on those, promise! ;)<=
br></div></div></div></div></div><div><span class=3D"gmail-im"></span></div=
></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Sat, De=
c 31, 2016 at 6:15 PM, Vicente J. Botet Escriba <span dir=3D"ltr"><<a hr=
ef=3D"mailto:vicente.botet@wanadoo.fr" target=3D"_blank">vicente.botet@wana=
doo.fr</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span class=3D"">
<div class=3D"m_2667955782052143795moz-cite-prefix">Le 31/12/2016 =C3=
=A0 15:57, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Dear Vincente,<br>
<br>
</div>
Thank you for your very in-depth review. I've updated the
proposal using already received comments from this thread,
so some things have changed, but it's still alright to
receive comments on this version. I'll explain below how
it has changed when answering to your comments.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">IIUC, every
occurrence of the base type in the definition of the
base type is replaced by the new type. This is one of
the options described in Opaque proposal (see The return
type issue). Why the other alternatives have less sens?<spa=
n class=3D"m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-5826156030849956333g=
mail-im"></span></blockquote>
<span class=3D"m_2667955782052143795m_-5826156030849956333gma=
il-im"> </span><br>
</div>
There are many differences between my proposal and the
Opaque proposal. I believe that the main ones that this
proposal brings are:<br>
<br>
</div>
- Where possible, do not introduce new meanings or rules to
the language. The type-copied class should behave as closely
as possible to a class the user has implemented by hand. This
should make very easy to understand how the feature works,
without the need to grasp many new concepts.<br>
</div>
- I have removed the option to modify and remove existing
functionality from the class that is being copied. While I
believe that this can be useful, it introduces too much
complexity in my opinion now. If this is allowed, you basically
have to create a system where you are allowed to completely
rewrite an existing class starting from another, since you may
want to copy or remove or change anything that was previously
present. This I believe can both make the proposal unnecessary
complicated, and can make the code very hard to follow, as at
each new strong-typedef step (since a type could be copied, and
the copy copied again and so on) anything could happen. I now
believe that an incremental-only strategy (similar to
inheritance) can still be both useful and sufficient for most
cases. Where it is not, simple implementations by hand of basic
functionality, extended then via the type-copy mechanism should
result in clear, reusable code which still requires little
maintenance.<br>
</div>
</blockquote></span>
To be honest, I will vote against this proposal if we can not modify
and delete existing functionality. When I copy/paste a class I can
change things and remove others.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><br>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The word du=
plicating
and wrapping don't match. The proposed approach doesn&#=
39;t
wraps the underlying type, except maybe for builtin
types.<br>
</blockquote>
<br>
</div>
<div>Right, I'll fix it, thanks.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I believe t=
he
proposal needs to add some concrete examples as use
cases<br>
</blockquote>
</div>
<div><br>
</div>
<div>This makes sense, I'll worn ok an additional section
where I try to show some concrete examples.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
The best will be to add them in the motivation section showing how
the new feature is used instead of some flat code.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">If the base=
class
change, the strong types depending on it could need
maintenance also, isn't it?<span class=3D"m_26679557820=
52143795m_-5826156030849956333gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True, however wrapper methods have to be fixed 100%
of the time, while a type-copied class may not need
this. It's the same as if one modified a base class in
inheritance - you don't have to necessarily update all
the code that depends on it right away.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
One of the problems of your proposal is that the copied class has
access to the private members, which is more subject to changes. I
believe that the copied class should only have access to public
members.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In additi=
on to
these basic techniques, there are other library
solution, as e.g. using CRTP that might merit to be
mentioned.<br>
See [TBoost.Opaque] for a possible implementation.<span c=
lass=3D"m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-582615603084995633=
3gmail-im"></span></blockquote>
<br>
</div>
<div>I'll add a mention to CRTP. I'll give a look at =
the
boost link, thanks!<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Please ad=
d <a class=3D"m_2667955782052143795m_-5826156030849956333gmail-m_-752264993=
0861642754moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1/sc22/=
wg21/docs/papers/2015/p0109r0.pdf" target=3D"_blank">http://www.open-std.or=
g/jtc1/s<wbr>c22/wg21/docs/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span class=3D"m_2667955782052143795m_-58261=
56030849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-582615603084995633=
3gmail-im"></span></blockquote>
<br>
</div>
<div>Thanks, I must have missed it.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">What is w=
rong for
you with p0109r0 approach?<br>
What we could have with your approach that we cannot
have with p0109r0?<br>
What we could have with p0109r0 that we cannot have
with your approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce any
operations by default other than conversions and your
proposal introduce all members but no friends<span class=
=3D"m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-582615603084995633=
3gmail-im"></span></blockquote>
<br>
</div>
<div>Personally, I don't think there's anything "=
;wrong"
with p0109r0. The idea for this proposal came to me
before I knew the alternatives, but since C++ still does
not have strong typedefs I thought I might as well
propose an alternative approach, which could possibly
garner more interest.<br>
<br>
</div>
<div>I believe my approach is simpler to read and more
intuitive - especially when creating strong aliases of
very complex types, but that can definitely be bias. It
can be applied to hierarchies of classes, since it
allows type-copying interdependent classes, which I
believe is very important. It is very easy to use with
templates and specializations, which potentially gives
it a lot of power and very many potential uses. It is
easily composable, as in copying a copy is very easy and
indeed expected in my view for the feature.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You will need to show how all this arguments applies on concrete
examples and how p0109r0 could do the same thing.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>With p0109r0 there's more flexibility to alter a
type. The additional flexibility allows it to take on
more tasks, as in type-copying friends, since default
ways to convert to the original types exist. It is
designed for primitive types first, while I have
actually removed them in my last iteration for a number
of reasons (see below). </div>
</div>
</div>
</div>
</div>
</blockquote></span>
Again, I will vote against this proposal if it doesn't provides a
solution for builtin types, as this is IMHO one of the most
appealing use cases.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The additional flexibility however comes at a cost,
as you mention the return type issue, which my proposal
does not have.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Your proposal has already this issue as you copy the whole class,
and so you replace every occurrence of the base class with the new
class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>I don't introduce friends mostly because a feature t=
o
create type-aliases of methods does not currently exist,
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I don't know what do you mean by type-aliases of methods. Could you
elaborate?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>and I don't believe it is wise to add it to the scop=
e
of this proposal since it would be another very large
change. If such a feature existed, however, adding
friends to a type-copied class in my proposal would be
trivial, as simply strong typedefs of the needed
functions could be created on the fly. The same could
also be done for non-member functions if needed, but how
that would work I have not thought about yet.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Could you elaborate how type-aliases of methods would help here?<span c=
lass=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I find th=
at
conversions to/from the underlying type must be
covered by the proposal. If we change the Base type we
don't want to be forced to redefine the conversion
operator.<br>
Maybe we need some kind of default conversion
implementation<br>
<span style=3D"font-family:courier new,monospace">=C2=A0=
=C2=A0=C2=A0
operator Base() <b>=3D default</b>;</span><br>
<span style=3D"font-family:courier new,monospace"> or </s=
pan><br>
<span style=3D"font-family:courier new,monospace">=C2=A0=
=C2=A0=C2=A0 <b>explicit</b>
operator Base() <b>=3D default</b>;</span><br>
</blockquote>
</div>
<div><br>
</div>
<div>I like this. I didn't add it to keep the number of
features as low as reasonably possible, but this is
simple enough. This could also be used recursively, as
in a copy of a copy could define a conversion operator
to both the first copy and the original in this way. </div>
</div>
</div>
</div>
</div>
</blockquote></span>
Could you elaborate?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a conversion
operator would be disabled if the copy has added new
attributes with respect to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Why?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Why do yo=
u
introduce this restriction? (on template parameter
numbers)<br>
</blockquote>
</div>
<div><br>
</div>
<div>No actually, you're right. I should lift it. I
thought initially that there wouldn't be any reason to
add more template parameters, as they would only be
needed to satisfy the original class. But this is
definitely wrong. I'll change it, thanks.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In ** abo=
ve C has
not yet defined as a copy<span class=3D"m_266795578205214=
3795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-582615603084995633=
3gmail-im"></span></blockquote>
<br>
</div>
<div>Ill explain how I believe this example should work.
Since C has been declared but not defined when parsing
D, the compiler will be allowed to assume that C is
going to be defined later as a type-copy of A. If that
does not happen, then the compiler will give an error,
either at the definition of C or of D, explaining that D
assumed that C would have been a type-copy while it was
not. If C has added new attributes to its declaration
though D's definition would need to take the new size o=
f
C into account though. Not sure if this can be done or
if it should result in an error.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I don't know compiler writers would like to look ahead. I believe
that C should be forward declared as a copy.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I believe=
this
interdependent case introduce a lot of complexity. We
would need a good use case to introduce it on the
standard.<span class=3D"m_2667955782052143795m_-582615603=
0849956333gmail-im"></span><br>
<span class=3D"m_2667955782052143795m_-582615603084995633=
3gmail-im"></span></blockquote>
<br>
</div>
<div>A very simple example would be copying of inherited
classes, both base and derived. Without a way to do this
that just cannot be done. This can be important if one
does not want that the derived type and its type-copy
are allowed to be converted to the same base. This is a
strong reason, I believe, otherwise strong-typing in
that case just lost some power in keeping original and
type-copy apart.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I will need a concrete example of when a complete hierarchy must be
"duplicated". I'm not saying there are no cases, just I h=
ave no one
in my head.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I believe=
that this
cannot be optional as in a lot of cases we need to
modify/restrict the base type interface.<br>
</blockquote>
<br>
</div>
<div>I have actually removed this in my newest revision. I
believe that ground-up building of types is the better
way to go (as is normally done in inheritance). Having
the power to completely alter the original type,
possibly to a point where there was not even much in
common between the original and the type-copy, is not
worth it. This is a personal opinion, but I believe
doing so can prevent some very complex and ugly code
smells, at a not incredible cost.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
We need to solve concrete problems. The 1st use case I have for
strongly types is to reduce the interface provided by the underlying
type and to adapt the functions signatures to the new class.<span class=
=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>Could you give a concrete example of this kind of
problems?<br>
</div>
</blockquote>
<div>
<div style=3D"margin-left:40px"><span class=3D"m_2667955782=
052143795m_-5826156030849956333gmail-im"></span></div>
<br>
</div>
<div>Suppose<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; =
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return f=
oo(x) * 4.0; }<br>
};<br>
</div>
<div><br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int foo(int) =3D delete;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // bar cannot compile anymore<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Where is the problem? struct B will not compile. That's all.<span c=
lass=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct C : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(int x) { return x * 2; }<b=
r>
</div>
<div>=C2=A0=C2=A0=C2=A0 // ambiguous definition<br>
};<br>
</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You are not modifying here, but adding ;-). You can say it is
ambiguous, but we have this case with inheritance
(<a class=3D"m_2667955782052143795moz-txt-link-freetext" href=3D"http:/=
/melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl" target=3D"_blank">http://mel=
pon.org/wandbox/<wbr>permlink/f9mRtE9n5mA9RPpl</a>)<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct D : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(double x) { return x * 3; =
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // Changes meaning of bar underhanded=
ly with no
warning<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I don't see a problem here as D is a copy of A and then we are
defining its meaning.<br>
You said that it should be as simple as if defined the class by
hand.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>I suppose even more dangerous and complex cases could
be devised.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
We will need some real examples to see how dangerous they are ;-)<span =
class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">While thi=
s is
inline with your approach, this merits some
explanations as the operators are no members.
Shouldn't the operators of UDT classes meritt to be
inherited as well?<br>
</blockquote>
<div><br>
</div>
<div>I've removed primitive type support also for this
reason. They are not currently treated as classes by
C++, and so I think I shouldn't either. Instead my
approach is now constructive. If one needed aliases
for primitive types, one could create a single header
of wrappers in the form<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>class SimpleWrapper {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 public:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 SimpleWrapp=
er(T t) : t_(t) {}<br>
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br>
</div>
<div>};<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>struct SimpleWrapperWithSum : using
SimpleWrapper<T> {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 SimpleWrapperWithSum operator+(cons=
t
SimpleWrapperWithSum & other) { return t_ +
other.t_; }<br>
</div>
<div>};<br>
<br>
</div>
<div>And so on. It would only be needed once, and then
users could simply copy the versions with the
operators they need to use. It's not incredibly prett=
y
and it does have some limitations, but it works, </div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe it is worth mentioning it in the proposal. My
TBoost.Opaque library implements something like that. I will start a
new thread to talk about the TBoost.Opaque library approach. If I
need a library solution for builtin types, why this library solution
will not work for classes, what will be the added value of the
language solution?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>and in any case even in p0109r0 one would need to
remove all unneeded operators, so work would need to
be done anyway. <br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
No p0109r0 doesn't define any operation by default (except
conversions). The user needs to add whatever is needed, maybe using
the default trampoline implementation). Well this is how I
understand it.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>I believed that there where no implicit
conversions on your proposals. How (*this) is
converted to an int?<br>
<br>
What would be the result type of x below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span class=3D"m_26679557=
82052143795m_-5826156030849956333gmail-im"></span><br>
</div>
</blockquote>
<div>
<blockquote><span class=3D"m_2667955782052143795m_-582615=
6030849956333gmail-im"></span></blockquote>
Yeah, this was a weird syntax, I thought it could be a
simple way to represent conversion to the underlying
primitive type.<br>
<br>
The type of the operation would be Id, yes. I believe
that to be the only intuitive result that makes sense,
unless an explicit operator+ that does a conversion
has been defined somewhere. If a cast is needed, one
needs to cast. I don't see a reason to change that fo=
r
strong typedefs, otherwise the language would be
inconsistent IMO.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Why thi=
s
restriction is needed or desirable.<span class=3D"m_266=
7955782052143795m_-5826156030849956333gmail-im"> (w.r.t.
final in type-copies of primitive types)<br>
</span></blockquote>
<div><br>
</div>
<div>It is not. But I believe that if one needs to do
something, it has to be in line with the rest of the
language. If a strong typedef of a primitive type is
needed, it would still need to follow the rules of
primitive types. </div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
It depends. If a strong type is able to define new members it is not
anymore a builtin and becomes for me a class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>As primitive types are not inheritable, I believe
neither should the strong typedefs. Maybe this is a
wrong position, I don't know (since primitive
typedefs are not inheritable due to C
compatibilities IIUC), but I believe that having
consistency is still useful for a proposal.
Otherwise one needs to always learn a million
exceptions to each rule, and that I don't like,
where it can be avoided. In any case, these are my
opinions, but if there is strong consensus to change
how the proposal works I have no problem in
modifying it.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You need to justify your decisions on a rationale section. But as
you have removed builtin types as base types this is not needed
anymore. You will need to justify why builtin are not supported :(=C2=
=A0
<br><span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0=
px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Examp=
le of
where this can be useful welcome.<br>
</blockquote>
<div><br>
</div>
<div>I must admit I didn't really think about this,
I just thought they could be nice to have. Maybe
they would be useless. I just considered that
sometimes the ingenuity of how people use tools
always seem to surprise, so why not. Maybe in
order to SFINAE the generation of conversion
operators to classes, given that they are copies
of the original? Something like<br>
<br>
</div>
<div>struct Copy : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 template <typename T, =
/*
enable_if_t<is_copy_of_v<T, A>>>
*/><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 operator T =3D default;<b=
r>
</div>
<div>};<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Features must be added to solve concrete problems.<br>
<br>
I suggest you to work on the motivation section with real concrete
examples.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">How=
other
type traits behave for the copied class (see
p0109r0)?<br>
</blockquote>
<br>
</div>
<div>All other type traits behave as if the class
had been implemented by hand, and is separate from
the original. so is_same would return false, for
example. It seems that p0109r0 thinks the same
way. The only difference is that sizeof may be
different, since in my proposal one could add
additional attributes to the type-copied class.
(There's no examples in the old version, I've
added them on GitHub though).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I agree for is_same of course. I was wondering for other traits that
could have been specialized for the base class. I suspect the answer
is that the user would need to specialize the new type again.<span clas=
s=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Thanks again for your feedback.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You are welcome,<br>
Vicente<br>
<br>
</div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-e5cf8b4ff3ca%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/f4a5=
7116-c65b-94f4-<wbr>51f2-e5cf8b4ff3ca%40wanadoo.fr</a><wbr>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtVBKZOMtpURNBDCEJijFL_J5s%=
2BROrLwJfkRgGyWzZMgg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
tVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com</a>.<br />
--001a114dae72ca72e10544f8a227--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sun, 1 Jan 2017 16:56:58 +0100
Raw View
This is a multi-part message in MIME format.
--------------AEDADE077498BC8C9124C5AA
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 31/12/2016 =C3=A0 19:39, Eugenio Bargiacchi a =C3=A9crit :
Eugenio, please, preserve some additional context in your responses.
From you responses, I believe that I have not understood your proposal.=20
See below (***)
>
> To be honest, I will vote against this proposal if we can not
> modify and delete existing functionality. When I copy/paste a
> class I can change things and remove others.
>
>
> I really understand this feeling. However, consider this: at which=20
> point is something a strong typedef of something else, and when is it=20
> a new class? Is the mechanism we want to introduce simply a way to=20
> declare a new class, using another as a starting point and completely=20
> editable, or we want there to be some kind of association (even if it=20
> was only on a logical level) between the two things?
I see that you want to add a new mechanism to define a new class using=20
another class as starting point, but I would not name this a strong type=20
proposal, even if it can be used to build some strong types. Whether=20
this is useful by itself needs more motivation and concrete real examples.
>
> A mechanism that freely allows you to edit classes wouldn't be a=20
> strong typedef, in my opinion. Consider:
>
> struct A {
> void foo();
> };
>
> struct B : using A {
> void foo() =3D delete;
> void bar();
> };
>
> Why would you have copied A in the first place then, rather than=20
> create a new class?
Add just N bazN() functions to A and you will see why it is interesting=20
to modify B because B doesn't want to provide the foo function, but all=20
the bazN functions.
> If instead you could say "copies can only add" then when you find a=20
> class declared as a copy you can easily reason about it. Think about a=20
> long chains of copies:
>
> struct A { /* .... */ };
> struct B : using A { /* .... */ };
> struct C : using B { /* .... */ };
> struct D : using C { /* .... */ };
> struct E : using D { /* .... */ };
>
> All these maybe in different files, in different places. Then what is=20
> E? If you are allowed to remove and change things, then you'd have to=20
> start at A and manually keep track of which things are deleted, maybe=20
> re-added later, maybe modified. It would be really hard to know=20
> exactly what E is. While if you're allowed to only increment, it would=20
> be much easier to know that - or at least on par with inheritance. If=20
> you can find it once in the chain, then it exists. I believe this is=20
> an important fact that must be considered when thinking about what=20
> features we want in strong typing.
Note that inheritance allows you to make a member not accessible.
struct A {
int foo(int x) { return x * 2; }
double bar(double x) { return foo(x) * 4.0; }
};
struct B : A {
private:
double bar(double x);
};
>
> One of the problems of your proposal is that the copied class has
> access to the private members, which is more subject to changes. I
> believe that the copied class should only have access to public
> members.
>
>
> If one creates a new class, and private members cannot be accessed,=20
> there will not be any way to touch them to do anything else aside from=20
> the original interface.
Right.
> This is also compounded by the fact that all old methods accepting the=20
> original class won't work on the new class (creating an operator=20
> Base() should be an exception for certain use-cases, it should not be=20
> necessary to do so).
The Base conversion can be protected or private. The trampoline would=20
take care of this conversions.
> How are you going to print a copy?
Hmm, using the public interface or don't.
> How can you convert in a custom way to the original class?
I don't see the use case. Maybe you have one.
> How are you going to implement additional and useful methods without=20
> access to privates?
If we need to access to private I believe it is worth creating a new class.
>
> Again, I will vote against this proposal if it doesn't provides a
> solution for builtin types, as this is IMHO one of the most
> appealing use cases.
>
>
> A solution exists, and is the one that already exists when one wants=20
> to limit operations done on existing types: build a wrapper. The=20
> difference is that before a completely new wrapper had to be built=20
> from scratch for each new needed primitive alias, depending on the=20
> required operations, with this proposal they become easily composable,=20
> so once done it never has to be done again, and adding new types=20
> becomes a one-liner for the user.
What I mean is that these wrappers should be part of the proposal and=20
show how the your copy class reach to make concrete and real opaque=20
types as e.g the energy example in P0109.
>
> Consider this against what p0109r0 does:
>
> template <class T =3D double>
> using energy =3D protected double {
> energy operator+ (energy , energy) =3D default;
> energy& operator*=3D(energy&, T ) =3D default;
> energy operator*(energy , energy) =3D delete;
> energy operator*(energy , T ) =3D default;
> energy operator*(T , energy) =3D default;
> };
>
> You see that in order to have a custom type, still many things must be=20
> written. So what's the difference between creating copyable wrappers=20
> (using normal C++ rules), and creating a number of such interfaces=20
> (having to learn and teach how protected/public/private work in a new=20
> context)? I don't see what the difference would be. Why do you feel=20
> that wrappers on primitive types are not enough?
Yes, the new opaque type must define all the available functions. Note=20
that p0109 provides conversions and the possibility to request the=20
compiler to generate the default trampolines. This is much sorter than=20
defining them using the current C++ language. Implicit conversions=20
(public) allow to use the new opaque type where the underlying type was=20
expected.
I would prefer the opaque type proposal to go even further (or an=20
independent proposal) and be able to introduce groups of trampolines as=20
I did on my Opaque library with the combined mixins. However I have no=20
concrete proposal at the language level.
> Your proposal has already this issue as you copy the whole class,
> and so you replace every occurrence of the base class with the new
> class.
>
>
> I'm not sure what you mean. In my proposal, the copy is a new class,=20
> and so it is always obvious what an assignment operator is going to=20
> result in. In p0109r0 this is more complex because depending on the=20
> access specifier different default conversion operators are defined.=20
> Not sure what you mean when you mention the replacement that happens,=20
> and what the issue is.
struct A {
A append(A const&);
};
struct B : using A {};
What will be the type of x
B b1, b2;
auto x =3D b1.append(b2);
IIUC your proposal, the append function will be copied replacing any=20
occurrence of A by B, so it is as if B was declared
struct B {
B append(B const&);
};
Am I missing something? (***)
Or would B equivalent to
struct B {
A append(B const&);
};
or to
struct B {
A append(A const&);
};
I'm wondering now if the copied class could add at all new non-static=20
data members. Otherwise I don't see how the duplication of such function=20
can be done. I suspect that p0109 doesn't allow to add new data.
Then, if the user wants to add more data, it should first duplicate the=20
class and then inherit from the duplicated class to add more data.
>
> I don't know what do you mean by type-aliases of methods. Could
> you elaborate?
>
>
> Yes. So consider this:
>
> struct A {
> friend void foo(A&);
> };
>
> struct B : using A {};
>
> To me the only way to allow B to also have the friend declaration is=20
> if we could do the following transformation:
>
> void foo(A&) ----> void foo(B&)
Right.
>
> In some sense creating a new foo overload using the type-copy.=20
> However, I believe this would be a pretty big change.
I believed this was already part of your proposal. (***)
> If such a thing was allowed, then why stop at copies? Why not being=20
> able to define
>
> void foo(A&) ----> void foo(C&)
>
> or even
>
> void foo(A&) ----> template<typename T> void foo(T&);
>
> As this is outside of the scope of my proposal, I did not include=20
> this. And so, I cannot add to my proposal the conversion of friend and=20
> non-member function when creating a copy-type. If this could be=20
> included, there would be no problem for that.
Sorry, I don't know yet what are type-aliases of methods.
>
> Could you elaborate? (on recursive conversion operator)
>
>
> For example, consider
>
> struct A {};
> struct B : using A {
> operator A() =3D default;
> };
> struct C : using B {
> operator B() =3D default;
> operator A() =3D default;
> };
>
> Just an idea.
I'm lost.
>
>> However, this default way to define a conversion operator would
>> be disabled if the copy has added new attributes with respect to
>> its original class.
> Why?
>
>
> I think that at that point the two classes diverged enough that the=20
> compiler cannot assume they can be converted freely? If I have:
>
> struct A { int x; };
> struct B : using A { int y; };
>
> Is it really wise to allow the compiler to be able to default convert=20
> B to A?
I would say, yes. The question p0109 raise is whether the user wants it.
> If they were the same, ok, but maybe at that point the user should be=20
> forced to provide a conversion operator, no?
If the user decides to provide the default implementation I don't see=20
where the problem is.
operator Base() =3D default;
The compiler know how to do the conversion.
>
> I don't know compiler writers would like to look ahead. I believe
> that C should be forward declared as a copy.
>
>
> Maybe. I thought that inherited classes are also declared without=20
> mentioning that they inherit, so I though that the same should hold=20
> for copies.
Maybe, but the C++ standard doesn't have constrains on whether the class=20
is derived from another class.
>
> I will need a concrete example of when a complete hierarchy must
> be "duplicated". I'm not saying there are no cases, just I have no
> one in my head.
>
>
> I'll try to add these on the concrete examples.
>
> You are not modifying here, but adding ;-). You can say it is
> ambiguous, but we have this case with inheritance
> (http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl
> <http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl>)
>
>
> Not quite, the resulting copied class would be equivalent to
>
> struct C {
> int foo(int x) { return x * 2; }
> double foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> which is illegal, since you cannot overload on return type. Keep in=20
> mind that there is no "layer" between the original class and what gets=20
> added to the copy.
You are right. I missed that all the function are copied. In this case,=20
either a function is not copied when there is an added function with the=20
same overloaded signature or the program is ill formed.
>
> I don't see a problem here as D is a copy of A and then we are
> defining its meaning.
> You said that it should be as simple as if defined the class by hand.
>
>
> That's true, and that's mostly what I don't like about giving the=20
> ability to modify copied existing methods. It is definitely=20
> non-obvious that this is happening. If you make a mistake, it will=20
> take a long time to figure out that you involuntarily modified the=20
> behavior of the original class. That's bad in my book.
Maybe you need something like override to state clearly that you want to=20
redefine the inherited behavior.
>
> I believe it is worth mentioning it in the proposal. My
> TBoost.Opaque library implements something like that. I will start
> a new thread to talk about the TBoost.Opaque library approach. If
> I need a library solution for builtin types, why this library
> solution will not work for classes, what will be the added value
> of the language solution?
>
>
> I believe that wrapper types are just as good as primitive types. This=20
> is also how it's always been in C++. The main problem was simply that=20
> doing this over and over and over was incredibly unwieldy. I don't=20
> believe that the reason why the older, in-C++ approaches didn't work=20
> is that they were creating wrappers rather than "primitive type=20
> aliases". This proposal eliminates the need for repetition as once=20
> done, it is done forever. A library like boost can pre-produce often=20
> used primitive types wrappers once in a single header, and be done=20
> forever.
>
> No p0109r0 doesn't define any operation by default (except
> conversions). The user needs to add whatever is needed, maybe
> using the default trampoline implementation). Well this is how I
> understand it.
>
>
> From the proposal: "Since all member functions of the underlying type=20
> are known to the compiler, we can take advantage of this and therefore=20
> propose that the compiler, by default, generate default versions of=20
> these trampolines."
I interpret this as the compiler could generate them by default, once=20
the user has requested it using the =3D default syntax. I agree the=20
proposal doesn't contain examples where this is clear enough.
Vicente
>
> On Sat, Dec 31, 2016 at 6:15 PM, Vicente J. Botet Escriba=20
> <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
>
> Le 31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit :
>> Dear Vincente,
>>
>> Thank you for your very in-depth review. I've updated the
>> proposal using already received comments from this thread, so
>> some things have changed, but it's still alright to receive
>> comments on this version. I'll explain below how it has changed
>> when answering to your comments.
>>
>> IIUC, every occurrence of the base type in the definition of
>> the base type is replaced by the new type. This is one of the
>> options described in Opaque proposal (see The return type
>> issue). Why the other alternatives have less sens?
>>
>>
>> There are many differences between my proposal and the Opaque
>> proposal. I believe that the main ones that this proposal brings are=
:
>>
>> - Where possible, do not introduce new meanings or rules to the
>> language. The type-copied class should behave as closely as
>> possible to a class the user has implemented by hand. This should
>> make very easy to understand how the feature works, without the
>> need to grasp many new concepts.
>> - I have removed the option to modify and remove existing
>> functionality from the class that is being copied. While I
>> believe that this can be useful, it introduces too much
>> complexity in my opinion now. If this is allowed, you basically
>> have to create a system where you are allowed to completely
>> rewrite an existing class starting from another, since you may
>> want to copy or remove or change anything that was previously
>> present. This I believe can both make the proposal unnecessary
>> complicated, and can make the code very hard to follow, as at
>> each new strong-typedef step (since a type could be copied, and
>> the copy copied again and so on) anything could happen. I now
>> believe that an incremental-only strategy (similar to
>> inheritance) can still be both useful and sufficient for most
>> cases. Where it is not, simple implementations by hand of basic
>> functionality, extended then via the type-copy mechanism should
>> result in clear, reusable code which still requires little
>> maintenance.
> To be honest, I will vote against this proposal if we can not
> modify and delete existing functionality. When I copy/paste a
> class I can change things and remove others.
>>
>> The word duplicating and wrapping don't match. The proposed
>> approach doesn't wraps the underlying type, except maybe for
>> builtin types.
>>
>>
>> Right, I'll fix it, thanks.
>>
>> I believe the proposal needs to add some concrete examples as
>> use cases
>>
>>
>> This makes sense, I'll worn ok an additional section where I try
>> to show some concrete examples.
> The best will be to add them in the motivation section showing how
> the new feature is used instead of some flat code.
>>
>> If the base class change, the strong types depending on it
>> could need maintenance also, isn't it?
>>
>>
>> True, however wrapper methods have to be fixed 100% of the time,
>> while a type-copied class may not need this. It's the same as if
>> one modified a base class in inheritance - you don't have to
>> necessarily update all the code that depends on it right away.
> One of the problems of your proposal is that the copied class has
> access to the private members, which is more subject to changes. I
> believe that the copied class should only have access to public
> members.
>>
>> In addition to these basic techniques, there are other
>> library solution, as e.g. using CRTP that might merit to be
>> mentioned.
>> See [TBoost.Opaque] for a possible implementation.
>>
>>
>> I'll add a mention to CRTP. I'll give a look at the boost link,
>> thanks!
>>
>> Please add
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.=
pdf
>> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0=
..pdf>
>> to this list.
>>
>>
>> Thanks, I must have missed it.
>>
>> What is wrong for you with p0109r0 approach?
>> What we could have with your approach that we cannot have
>> with p0109r0?
>> What we could have with p0109r0 that we cannot have with your
>> approach?
>>
>> IIUC, p0109r0 opaque types don't introduce any operations by
>> default other than conversions and your proposal introduce
>> all members but no friends
>>
>>
>> Personally, I don't think there's anything "wrong" with p0109r0.
>> The idea for this proposal came to me before I knew the
>> alternatives, but since C++ still does not have strong typedefs I
>> thought I might as well propose an alternative approach, which
>> could possibly garner more interest.
>>
>> I believe my approach is simpler to read and more intuitive -
>> especially when creating strong aliases of very complex types,
>> but that can definitely be bias. It can be applied to hierarchies
>> of classes, since it allows type-copying interdependent classes,
>> which I believe is very important. It is very easy to use with
>> templates and specializations, which potentially gives it a lot
>> of power and very many potential uses. It is easily composable,
>> as in copying a copy is very easy and indeed expected in my view
>> for the feature.
> You will need to show how all this arguments applies on concrete
> examples and how p0109r0 could do the same thing.
>>
>> With p0109r0 there's more flexibility to alter a type. The
>> additional flexibility allows it to take on more tasks, as in
>> type-copying friends, since default ways to convert to the
>> original types exist. It is designed for primitive types first,
>> while I have actually removed them in my last iteration for a
>> number of reasons (see below).
> Again, I will vote against this proposal if it doesn't provides a
> solution for builtin types, as this is IMHO one of the most
> appealing use cases.
>> The additional flexibility however comes at a cost, as you
>> mention the return type issue, which my proposal does not have.
> Your proposal has already this issue as you copy the whole class,
> and so you replace every occurrence of the base class with the new
> class.
>>
>> I don't introduce friends mostly because a feature to create
>> type-aliases of methods does not currently exist,
> I don't know what do you mean by type-aliases of methods. Could
> you elaborate?
>> and I don't believe it is wise to add it to the scope of this
>> proposal since it would be another very large change. If such a
>> feature existed, however, adding friends to a type-copied class
>> in my proposal would be trivial, as simply strong typedefs of the
>> needed functions could be created on the fly. The same could also
>> be done for non-member functions if needed, but how that would
>> work I have not thought about yet.
> Could you elaborate how type-aliases of methods would help here?
>>
>> I find that conversions to/from the underlying type must be
>> covered by the proposal. If we change the Base type we don't
>> want to be forced to redefine the conversion operator.
>> Maybe we need some kind of default conversion implementation
>> operator Base() *=3D default*;
>> or
>> *explicit* operator Base() *=3D default*;
>>
>>
>> I like this. I didn't add it to keep the number of features as
>> low as reasonably possible, but this is simple enough. This could
>> also be used recursively, as in a copy of a copy could define a
>> conversion operator to both the first copy and the original in
>> this way.
> Could you elaborate?
>> However, this default way to define a conversion operator would
>> be disabled if the copy has added new attributes with respect to
>> its original class.
> Why?
>>
>> Why do you introduce this restriction? (on template parameter
>> numbers)
>>
>>
>> No actually, you're right. I should lift it. I thought initially
>> that there wouldn't be any reason to add more template
>> parameters, as they would only be needed to satisfy the original
>> class. But this is definitely wrong. I'll change it, thanks.
>>
>> In ** above C has not yet defined as a copy
>>
>>
>> Ill explain how I believe this example should work. Since C has
>> been declared but not defined when parsing D, the compiler will
>> be allowed to assume that C is going to be defined later as a
>> type-copy of A. If that does not happen, then the compiler will
>> give an error, either at the definition of C or of D, explaining
>> that D assumed that C would have been a type-copy while it was
>> not. If C has added new attributes to its declaration though D's
>> definition would need to take the new size of C into account
>> though. Not sure if this can be done or if it should result in an
>> error.
> I don't know compiler writers would like to look ahead. I believe
> that C should be forward declared as a copy.
>>
>> I believe this interdependent case introduce a lot of
>> complexity. We would need a good use case to introduce it on
>> the standard.
>>
>>
>> A very simple example would be copying of inherited classes, both
>> base and derived. Without a way to do this that just cannot be
>> done. This can be important if one does not want that the derived
>> type and its type-copy are allowed to be converted to the same
>> base. This is a strong reason, I believe, otherwise strong-typing
>> in that case just lost some power in keeping original and
>> type-copy apart.
> I will need a concrete example of when a complete hierarchy must
> be "duplicated". I'm not saying there are no cases, just I have no
> one in my head.
>>
>> I believe that this cannot be optional as in a lot of cases
>> we need to modify/restrict the base type interface.
>>
>>
>> I have actually removed this in my newest revision. I believe
>> that ground-up building of types is the better way to go (as is
>> normally done in inheritance). Having the power to completely
>> alter the original type, possibly to a point where there was not
>> even much in common between the original and the type-copy, is
>> not worth it. This is a personal opinion, but I believe doing so
>> can prevent some very complex and ugly code smells, at a not
>> incredible cost.
> We need to solve concrete problems. The 1st use case I have for
> strongly types is to reduce the interface provided by the
> underlying type and to adapt the functions signatures to the new
> class.
>>
>> Could you give a concrete example of this kind of problems?
>>
>>
>> Suppose
>>
>> struct A {
>> int foo(int x) { return x * 2; }
>> double bar(double x) { return foo(x) * 4.0; }
>> };
>>
>> struct B : using A {
>> int foo(int) =3D delete;
>> // bar cannot compile anymore
>> };
>>
> Where is the problem? struct B will not compile. That's all.
>> struct C : using A {
>> double foo(int x) { return x * 2; }
>> // ambiguous definition
>> };
>>
> You are not modifying here, but adding ;-). You can say it is
> ambiguous, but we have this case with inheritance
> (http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl
> <http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl>)
>> struct D : using A {
>> double foo(double x) { return x * 3; }
>> // Changes meaning of bar underhandedly with no warning
>> };
>>
> I don't see a problem here as D is a copy of A and then we are
> defining its meaning.
> You said that it should be as simple as if defined the class by hand.
>> I suppose even more dangerous and complex cases could be devised.
> We will need some real examples to see how dangerous they are ;-)
>>
>> While this is inline with your approach, this merits some
>> explanations as the operators are no members. Shouldn't the
>> operators of UDT classes meritt to be inherited as well?
>>
>>
>> I've removed primitive type support also for this reason. They
>> are not currently treated as classes by C++, and so I think I
>> shouldn't either. Instead my approach is now constructive. If one
>> needed aliases for primitive types, one could create a single
>> header of wrappers in the form
>>
>> template <typename T>
>> class SimpleWrapper {
>> public:
>> SimpleWrapper(T t) : t_(t) {}
>>
>> private:
>> T t_;
>> };
>>
>> template <typename T>
>> struct SimpleWrapperWithSum : using SimpleWrapper<T> {
>> SimpleWrapperWithSum operator+(const SimpleWrapperWithSum &
>> other) { return t_ + other.t_; }
>> };
>>
>> And so on. It would only be needed once, and then users could
>> simply copy the versions with the operators they need to use.
>> It's not incredibly pretty and it does have some limitations, but
>> it works,
> I believe it is worth mentioning it in the proposal. My
> TBoost.Opaque library implements something like that. I will start
> a new thread to talk about the TBoost.Opaque library approach. If
> I need a library solution for builtin types, why this library
> solution will not work for classes, what will be the added value
> of the language solution?
>> and in any case even in p0109r0 one would need to remove all
>> unneeded operators, so work would need to be done anyway.
> No p0109r0 doesn't define any operation by default (except
> conversions). The user needs to add whatever is needed, maybe
> using the default trampoline implementation). Well this is how I
> understand it.
>>
>> I believed that there where no implicit conversions on your
>> proposals. How (*this) is converted to an int?
>>
>> What would be the result type of x below?
>>
>> Id id(1);
>> auto x =3D +id;
>>
>> I suspect that it would be Id.
>>
>> Yeah, this was a weird syntax, I thought it could be a simple way
>> to represent conversion to the underlying primitive type.
>>
>> The type of the operation would be Id, yes. I believe that to be
>> the only intuitive result that makes sense, unless an explicit
>> operator+ that does a conversion has been defined somewhere. If a
>> cast is needed, one needs to cast. I don't see a reason to change
>> that for strong typedefs, otherwise the language would be
>> inconsistent IMO.
>>
>> Why this restriction is needed or desirable.(w.r.t. final in
>> type-copies of primitive types)
>>
>>
>> It is not. But I believe that if one needs to do something, it
>> has to be in line with the rest of the language. If a strong
>> typedef of a primitive type is needed, it would still need to
>> follow the rules of primitive types.
> It depends. If a strong type is able to define new members it is
> not anymore a builtin and becomes for me a class.
>> As primitive types are not inheritable, I believe neither should
>> the strong typedefs. Maybe this is a wrong position, I don't know
>> (since primitive typedefs are not inheritable due to C
>> compatibilities IIUC), but I believe that having consistency is
>> still useful for a proposal. Otherwise one needs to always learn
>> a million exceptions to each rule, and that I don't like, where
>> it can be avoided. In any case, these are my opinions, but if
>> there is strong consensus to change how the proposal works I have
>> no problem in modifying it.
> You need to justify your decisions on a rationale section. But as
> you have removed builtin types as base types this is not needed
> anymore. You will need to justify why builtin are not supported :(
>>
>> Example of where this can be useful welcome.
>>
>>
>> I must admit I didn't really think about this, I just thought
>> they could be nice to have. Maybe they would be useless. I just
>> considered that sometimes the ingenuity of how people use tools
>> always seem to surprise, so why not. Maybe in order to SFINAE the
>> generation of conversion operators to classes, given that they
>> are copies of the original? Something like
>>
>> struct Copy : using A {
>> template <typename T, /* enable_if_t<is_copy_of_v<T, A>>> */>
>> operator T =3D default;
>> };
> Features must be added to solve concrete problems.
>
> I suggest you to work on the motivation section with real concrete
> examples.
>>
>> How other type traits behave for the copied class (see p0109r0)?
>>
>>
>> All other type traits behave as if the class had been implemented
>> by hand, and is separate from the original. so is_same would
>> return false, for example. It seems that p0109r0 thinks the same
>> way. The only difference is that sizeof may be different, since
>> in my proposal one could add additional attributes to the
>> type-copied class. (There's no examples in the old version, I've
>> added them on GitHub though).
> I agree for is_same of course. I was wondering for other traits
> that could have been specialized for the base class. I suspect the
> answer is that the user would need to specialize the new type again.
>>
>> Thanks again for your feedback.
> You are welcome,
> Vicente
>
> --=20
> 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/gkJUVnL-=
Fmg/unsubscribe
> <https://groups.google.com/a/isocpp.org/d/topic/std-proposals/gkJUVnL=
-Fmg/unsubscribe>.
> To unsubscribe from this group and all its topics, send an email
> to std-proposals+unsubscribe@isocpp.org
> <mailto:std-proposals+unsubscribe@isocpp.org>.
> To post to this group, send email to std-proposals@isocpp.org
> <mailto:std-proposals@isocpp.org>.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a57116=
-c65b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a5711=
6-c65b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.fr?utm_medium=3Demail&utm_source=3D=
footer>.
>
>
> --=20
> You received this message because you are subscribed to the Google=20
> Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send=20
> an email to std-proposals+unsubscribe@isocpp.org=20
> <mailto:std-proposals+unsubscribe@isocpp.org>.
> To post to this group, send email to std-proposals@isocpp.org=20
> <mailto:std-proposals@isocpp.org>.
> To view this discussion on the web visit=20
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bt=
VBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com=20
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
tVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>.
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/ef8190c7-f46f-cf76-7e45-2114a84eae27%40wanadoo.f=
r.
--------------AEDADE077498BC8C9124C5AA
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 31/12/2016 =C3=A0 19:39, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
<br>
Eugenio, please, preserve some additional context in your
responses.<br>
<br>
From you responses, I believe that I have not understood your
proposal. See below (***)<br>
</div>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">To
be honest, I will vote against this proposal if we can not
modify and delete existing functionality. When I copy/paste a
class I can change things and remove others.<span
class=3D"gmail-im"></span><br>
</blockquote>
<div><br>
</div>
<div>I really understand this feeling. However, consider this:
at which point is something a strong typedef of something
else, and when is it a new class? Is the mechanism we want to
introduce simply a way to declare a new class, using another
as a starting point and completely editable, or we want there
to be some kind of association (even if it was only on a
logical level) between the two things?<br>
</div>
</div>
</blockquote>
I see that you want to add a new mechanism to define a new class
using another class as starting point, but I would not name this a
strong type proposal, even if it can be used to build some strong
types. Whether this is useful by itself needs more motivation and
concrete real examples.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><br>
</div>
<div>A mechanism that freely allows you to edit classes wouldn't
be a strong typedef, in my opinion. Consider:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void foo();<br>
};<br>
<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void bar();<br>
};<br>
<br>
</div>
<div>Why would you have copied A in the first place then, rather
than create a new class? </div>
</div>
</blockquote>
Add just N bazN() functions to A and you will see why it is
interesting to modify B because B doesn't want to provide the foo
function, but all the bazN functions.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>If instead you could say "copies can only add" then when
you find a class declared as a copy you can easily reason
about it. Think about a long chains of copies:<br>
<br>
</div>
<div>struct A { /* .... */ };<br>
struct B : using A { /* .... */ };<br>
struct C : using B { /* .... */ };<br>
struct D : using C { /* .... */ };<br>
struct E : using D { /* .... */ };<br>
<br>
</div>
</div>
</blockquote>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>All these maybe in different files, in different places.
Then what is E? If you are allowed to remove and change
things, then you'd have to start at A and manually keep track
of which things are deleted, maybe re-added later, maybe
modified. It would be really hard to know exactly what E is.
While if you're allowed to only increment, it would be much
easier to know that - or at least on par with inheritance. If
you can find it once in the chain, then it exists. I believe
this is an important fact that must be considered when
thinking about what features we want in strong typing.<br>
</div>
</div>
</blockquote>
Note that inheritance allows you to make a member not accessible.<br>
struct A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; }<br>
=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return foo(x) * 4.0; }<=
br>
};<br>
<br>
struct B : A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x);<br>
};<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">One of the problems of
your proposal is that the copied class has access to the
private members, which is more subject to changes. I believe
that the copied class should only have access to public
members.</blockquote>
<div><br>
</div>
If one creates a new class, and private members cannot be
accessed, there will not be any way to touch them to do
anything else aside from the original interface. </div>
</div>
</blockquote>
Right.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>This is also compounded by the fact that all old methods
accepting the original class won't work on the new class
(creating an operator Base() should be an exception for
certain use-cases, it should not be necessary to do so). </div>
</div>
</blockquote>
The Base conversion can be protected or private. The trampoline
would take care of this conversions.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>How are you going to print a copy? </div>
</div>
</blockquote>
Hmm, using the public interface or don't.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>How can you convert in a custom way to the original class?</di=
v>
</div>
</blockquote>
I don't see the use case. Maybe you have one.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div> How are you going to implement additional and useful
methods without access to privates?<br>
</div>
</div>
</blockquote>
If we need to access to private I believe it is worth creating a new
class. <br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><span class=3D"gmail-im"></span><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Again, I will vote
against this proposal if it doesn't provides a solution for
builtin types, as this is IMHO one of the most appealing use
cases.<span class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>A solution exists, and is the one that already exists when
one wants to limit operations done on existing types: build a
wrapper. The difference is that before a completely new
wrapper had to be built from scratch for each new needed
primitive alias, depending on the required operations, with
this proposal they become easily composable, so once done it
never has to be done again, and adding new types becomes a
one-liner for the user.<br>
</div>
</div>
</blockquote>
What I mean is that these wrappers should be part of the proposal
and show how the your copy class reach to make concrete and real
opaque types as e.g the energy example in P0109.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><br>
</div>
<div>Consider this against what p0109r0 does:<br>
<br>
<div style=3D"left: 153.208px; top: 609.361px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">template
<class T =3D double></span></font></div>
<div style=3D"left: 153.208px; top: 629.286px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">using
energy =3D protected double {</span></font></div>
<div style=3D"left: 173.135px; top: 649.211px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=
=A0=C2=A0
energy operator+ (energy , energy) =3D default;</span></fon=
t></div>
<div style=3D"left: 342.502px; top: 669.136px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=
=A0=C2=A0
energy& operator*=3D(energy&, T ) =3D default;</spa=
n></font></div>
<div style=3D"left: 352.463px; top: 689.062px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=
=A0=C2=A0
energy operator*(energy , energy) =3D delete;</span></font>=
</div>
<div style=3D"left: 352.463px; top: 708.987px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=
=A0=C2=A0
energy operator*(energy , T ) =3D default;</span></font></d=
iv>
<div style=3D"left: 352.463px; top: 728.912px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">=C2=A0=C2=
=A0=C2=A0
energy operator*(T , energy) =3D default;</span></font></di=
v>
<div style=3D"left: 153.208px; top: 748.837px; transform:
scaleX(0.99626);"><font size=3D"2"><span
style=3D"font-family:arial,helvetica,sans-serif">};</span><=
/font></div>
<br>
</div>
<div>You see that in order to have a custom type, still many
things must be written. So what's the difference between
creating copyable wrappers (using normal C++ rules), and
creating a number of such interfaces (having to learn and
teach how protected/public/private work in a new context)? I
don't see what the difference would be. Why do you feel that
wrappers on primitive types are not enough?<br>
</div>
</div>
</blockquote>
Yes, the new opaque type must define all the available functions.
Note that p0109 provides conversions and the possibility to request
the compiler to generate the default trampolines. This is much
sorter than defining them using the current C++ language. Implicit
conversions (public) allow to use the new opaque type where the
underlying type was expected. <br>
<br>
I would prefer the opaque type proposal to go even further (or an
independent proposal) and be able to introduce groups of trampolines
as I did on my Opaque library with the combined mixins. However I
have no concrete proposal at the language level. <br>
<font size=3D"2"><span style=3D"font-family:arial,helvetica,sans-serif"=
><br>
</span></font>
<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Your proposal has already
this issue as you copy the whole class, and so you replace
every occurrence of the base class with the new class.<span
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I'm not sure what you mean. In my proposal, the copy is a
new class, and so it is always obvious what an assignment
operator is going to result in. In p0109r0 this is more
complex because depending on the access specifier different
default conversion operators are defined. Not sure what you
mean when you mention the replacement that happens, and what
the issue is.<br>
</div>
</div>
</div>
</blockquote>
<br>
<br>
<div>struct A {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
struct B : using A {};<br>
<br>
What will be the type of x<br>
<br>
B b1, b2;<br>
auto x =3D b1.append(b2);<br>
<br>
IIUC your proposal, the append function will be copied replacing any
occurrence of A by B, so it is as if B was declared<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
Am I missing something? (***)<br>
<br>
Or would B equivalent to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(B const&);<br>
};<br>
<br>
or to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
I'm wondering now if the copied class could add at all new
non-static data members. Otherwise I don't see how the duplication
of such function can be done. I suspect that p0109 doesn't allow to
add new data.<br>
Then, if the user wants to add more data, it should first duplicate
the class and then inherit from the duplicated class to add more
data.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I don't know what do
you mean by type-aliases of methods. Could you elaborate?<spa=
n
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Yes. So consider this:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0 =C2=A0 friend void foo(A&);<br>
};<br>
<br>
</div>
struct B : using A {};<br>
<br>
</div>
<div>To me the only way to allow B to also have the friend
declaration is if we could do the following transformation:<br>
<br>
</div>
<div>void foo(A&) ----> void foo(B&)<br>
</div>
</div>
</div>
</blockquote>
Right.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
</div>
<div>In some sense creating a new foo overload using the
type-copy. However, I believe this would be a pretty big
change. </div>
</div>
</div>
</blockquote>
I believed this was already part of your proposal. (***)<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>If such a thing was allowed, then why stop at copies? Why
not being able to define<br>
<br>
</div>
<div>void foo(A&) ----> void foo(C&)<br>
<br>
</div>
<div>or even<br>
<br>
</div>
<div>void foo(A&) ----> template<typename T> void
foo(T&);<br>
<br>
</div>
<div>As this is outside of the scope of my proposal, I did not
include this. And so, I cannot add to my proposal the
conversion of friend and non-member function when creating a
copy-type. If this could be included, there would be no
problem for that.<br>
</div>
</div>
</div>
</blockquote>
Sorry, I don't know yet what are type-aliases of methods.
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Could you elaborate?
(on recursive conversion operator)<span class=3D"gmail-im"><b=
r>
</span></blockquote>
<div><br>
</div>
<div>For example, consider<br>
<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
</div>
<div>};<br>
</div>
<div>struct C : using B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator B() =3D default;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
};<br>
<br>
</div>
<div>Just an idea.<br>
</div>
</div>
</div>
</div>
</blockquote>
I'm lost.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a
conversion operator would be disabled if
the copy has added new attributes with
respect to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Why?<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I think that at that point the two classes diverged
enough that the compiler cannot assume they can be
converted freely? If I have:<br>
<br>
</div>
<div>struct A { int x; };<br>
</div>
<div>struct B : using A { int y; };<br>
<br>
</div>
<div>Is it really wise to allow the compiler to be able to
default convert B to A? </div>
</div>
</div>
</div>
</div>
</blockquote>
I would say, yes. The question p0109 raise is whether the user wants
it.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>If they were the same, ok, but maybe at that point
the user should be forced to provide a conversion
operator, no?<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
If the user decides to provide the default implementation I don't
see where the problem is.<br>
<br>
operator Base() =3D default;<br>
<br>
The compiler know how to do the conversion.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I don't know
compiler writers would like to look ahead. I believe
that C should be forward declared as a copy.<span
class=3D"gmail-im"><br>
</span></blockquote>
<br>
</div>
<div>Maybe. I thought that inherited classes are also
declared without mentioning that they inherit, so I
though that the same should hold for copies.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Maybe, but the C++ standard doesn't have constrains on whether the
class is derived from another class.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I will need a
concrete example of when a complete hierarchy must be
"duplicated". I'm not saying there are no cases, just
I have no one in my head.<span class=3D"gmail-im"></span>=
<br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>I'll try to add these on the concrete examples.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">You are not
modifying here, but adding ;-). You can say it is
ambiguous, but we have this case with inheritance (<a
moz-do-not-send=3D"true"
class=3D"gmail-m_2667955782052143795moz-txt-link-freete=
xt"
href=3D"http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl"
target=3D"_blank">http://melpon.org/wandbox/<wbr>permli=
nk/f9mRtE9n5mA9RPpl</a>)<span
class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>Not quite, the resulting copied class would be
equivalent to<br>
<br>
</div>
<div>
<div>struct C {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2=
; }<br>
<span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0=C2=A0 double =
foo(int x) { return
x * 2; }</span><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return=
foo(x) * 4.0; }<br>
};<br>
<br>
</div>
<div>which is illegal, since you cannot overload on
return type. Keep in mind that there is no "layer"
between the original class and what gets added to the
copy.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You are right. I missed that all the function are copied. In this
case, either a function is not copied when there is an added
function with the same overloaded signature or the program is ill
formed.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I don't see a
problem here as D is a copy of A and then we are
defining its meaning.<br>
You said that it should be as simple as if defined
the class by hand.<span class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>That's true, and that's mostly what I don't like
about giving the ability to modify copied existing
methods. It is definitely non-obvious that this is
happening. If you make a mistake, it will take a long
time to figure out that you involuntarily modified the
behavior of the original class. That's bad in my book.<br=
>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Maybe you need something like override to state clearly that you
want to redefine the inherited behavior.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I believe it is
worth mentioning it in the proposal. My
TBoost.Opaque library implements something like
that. I will start a new thread to talk about the
TBoost.Opaque library approach. If I need a library
solution for builtin types, why this library
solution will not work for classes, what will be the
added value of the language solution?<span
class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>I believe that wrapper types are just as good as
primitive types. This is also how it's always been in
C++. The main problem was simply that doing this over
and over and over was incredibly unwieldy. I don't
believe that the reason why the older, in-C++
approaches didn't work is that they were creating
wrappers rather than "primitive type aliases". This
proposal eliminates the need for repetition as once
done, it is done forever. A library like boost can
pre-produce often used primitive types wrappers once
in a single header, and be done forever.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">No p0109r0
doesn't define any operation by default (except
conversions). The user needs to add whatever is
needed, maybe using the default trampoline
implementation). Well this is how I understand it.<span
class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>From the proposal: "<span
style=3D"font-family:arial,helvetica,sans-serif"><font
size=3D"2">Since all member functions of the
underlying type are known to the compiler, we can
take advantage of this and therefore propose that
the compiler, </font></span><span
style=3D"font-family:arial,helvetica,sans-serif"><font
size=3D"2">by default, generate default versions of
these trampolines."<br>
</font></span></div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<font size=3D"2">I interpret this as the compiler could generate them
by default, once the user has requested it using the =3D default
syntax. I agree the proposal doesn't contain examples where this
is clear enough.</font><br>
<br>
<br>
<br>
Vicente<br>
<blockquote
cite=3D"mid:CAHfn=3D+tVBKZOMtpURNBDCEJijFL_J5s+ROrLwJfkRgGyWzZMgg@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><span class=3D"gmail-im"></span></div>
</div>
<div class=3D"gmail_extra"><br>
<div class=3D"gmail_quote">On Sat, Dec 31, 2016 at 6:15 PM,
Vicente J. Botet Escriba <span dir=3D"ltr"><<a
moz-do-not-send=3D"true"
href=3D"mailto:vicente.botet@wanadoo.fr" target=3D"_blank">vi=
cente.botet@wanadoo.fr</a>></span>
wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span class=3D"">
<div class=3D"m_2667955782052143795moz-cite-prefix">Le
31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit=
=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Dear Vincente,<br>
<br>
</div>
Thank you for your very in-depth review. I've
updated the proposal using already received
comments from this thread, so some things have
changed, but it's still alright to receive
comments on this version. I'll explain below
how it has changed when answering to your
comments.<br>
<br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">IIUC,
every occurrence of the base type in the
definition of the base type is replaced by
the new type. This is one of the options
described in Opaque proposal (see The return
type issue). Why the other alternatives have
less sens?<span
class=3D"m_2667955782052143795m_-582615603084=
9956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-582615603084=
9956333gmail-im"></span></blockquote>
<span
class=3D"m_2667955782052143795m_-58261560308499=
56333gmail-im">
</span><br>
</div>
There are many differences between my proposal
and the Opaque proposal. I believe that the main
ones that this proposal brings are:<br>
<br>
</div>
- Where possible, do not introduce new meanings or
rules to the language. The type-copied class
should behave as closely as possible to a class
the user has implemented by hand. This should make
very easy to understand how the feature works,
without the need to grasp many new concepts.<br>
</div>
- I have removed the option to modify and remove
existing functionality from the class that is being
copied. While I believe that this can be useful, it
introduces too much complexity in my opinion now. If
this is allowed, you basically have to create a
system where you are allowed to completely rewrite
an existing class starting from another, since you
may want to copy or remove or change anything that
was previously present. This I believe can both make
the proposal unnecessary complicated, and can make
the code very hard to follow, as at each new
strong-typedef step (since a type could be copied,
and the copy copied again and so on) anything could
happen. I now believe that an incremental-only
strategy (similar to inheritance) can still be both
useful and sufficient for most cases. Where it is
not, simple implementations by hand of basic
functionality, extended then via the type-copy
mechanism should result in clear, reusable code
which still requires little maintenance.<br>
</div>
</blockquote>
</span> To be honest, I will vote against this proposal if
we can not modify and delete existing functionality. When
I copy/paste a class I can change things and remove
others.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><br>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">The word
duplicating and wrapping don't match. The
proposed approach doesn't wraps the
underlying type, except maybe for builtin
types.<br>
</blockquote>
<br>
</div>
<div>Right, I'll fix it, thanks.<br>
<br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I believe
the proposal needs to add some concrete
examples as use cases<br>
</blockquote>
</div>
<div><br>
</div>
<div>This makes sense, I'll worn ok an
additional section where I try to show some
concrete examples.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> The best will be to add them in the motivation
section showing how the new feature is used instead of
some flat code.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">If the
base class change, the strong types
depending on it could need maintenance also,
isn't it?<span
class=3D"m_2667955782052143795m_-582615603084=
9956333gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True, however wrapper methods have to be
fixed 100% of the time, while a type-copied
class may not need this. It's the same as if
one modified a base class in inheritance -
you don't have to necessarily update all the
code that depends on it right away.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> One of the problems of your proposal is that the
copied class has access to the private members, which is
more subject to changes. I believe that the copied class
should only have access to public members.<span class=3D""><b=
r>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">In
addition to these basic techniques, there
are other library solution, as e.g. using
CRTP that might merit to be mentioned.<br>
See [TBoost.Opaque] for a possible
implementation.<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></blockquote>
<br>
</div>
<div>I'll add a mention to CRTP. I'll give a
look at the boost link, thanks!<br>
<br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Please
add <a moz-do-not-send=3D"true"
class=3D"m_2667955782052143795m_-5826156030849956333gmail-m_-75226499308616=
42754moz-txt-link-freetext"
href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf=
"
target=3D"_blank">http://www.open-std.org/j=
tc1/s<wbr>c22/wg21/docs/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Thanks, I must have missed it.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">What is
wrong for you with p0109r0 approach?<br>
What we could have with your approach that
we cannot have with p0109r0?<br>
What we could have with p0109r0 that we
cannot have with your approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduce
any operations by default other than
conversions and your proposal introduce
all members but no friends<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Personally, I don't think there's
anything "wrong" with p0109r0. The idea for
this proposal came to me before I knew the
alternatives, but since C++ still does not
have strong typedefs I thought I might as
well propose an alternative approach, which
could possibly garner more interest.<br>
<br>
</div>
<div>I believe my approach is simpler to read
and more intuitive - especially when
creating strong aliases of very complex
types, but that can definitely be bias. It
can be applied to hierarchies of classes,
since it allows type-copying interdependent
classes, which I believe is very important.
It is very easy to use with templates and
specializations, which potentially gives it
a lot of power and very many potential uses.
It is easily composable, as in copying a
copy is very easy and indeed expected in my
view for the feature.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You will need to show how all this arguments
applies on concrete examples and how p0109r0 could do the
same thing.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>With p0109r0 there's more flexibility to
alter a type. The additional flexibility
allows it to take on more tasks, as in
type-copying friends, since default ways to
convert to the original types exist. It is
designed for primitive types first, while I
have actually removed them in my last
iteration for a number of reasons (see
below). </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Again, I will vote against this proposal if it
doesn't provides a solution for builtin types, as this is
IMHO one of the most appealing use cases.<span class=3D""><br=
>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The additional flexibility however comes
at a cost, as you mention the return type
issue, which my proposal does not have.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Your proposal has already this issue as you copy
the whole class, and so you replace every occurrence of
the base class with the new class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>I don't introduce friends mostly because
a feature to create type-aliases of methods
does not currently exist, </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't know what do you mean by type-aliases of
methods. Could you elaborate?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>and I don't believe it is wise to add it
to the scope of this proposal since it would
be another very large change. If such a
feature existed, however, adding friends to
a type-copied class in my proposal would be
trivial, as simply strong typedefs of the
needed functions could be created on the
fly. The same could also be done for
non-member functions if needed, but how that
would work I have not thought about yet.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Could you elaborate how type-aliases of methods
would help here?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I find
that conversions to/from the underlying
type must be covered by the proposal. If
we change the Base type we don't want to
be forced to redefine the conversion
operator.<br>
Maybe we need some kind of default
conversion implementation<br>
<span style=3D"font-family:courier
new,monospace">=C2=A0=C2=A0=C2=A0 operator =
Base() <b>=3D
default</b>;</span><br>
<span style=3D"font-family:courier
new,monospace"> or </span><br>
<span style=3D"font-family:courier
new,monospace">=C2=A0=C2=A0=C2=A0 <b>explic=
it</b>
operator Base() <b>=3D default</b>;</span><=
br>
</blockquote>
</div>
<div><br>
</div>
<div>I like this. I didn't add it to keep the
number of features as low as reasonably
possible, but this is simple enough. This
could also be used recursively, as in a copy
of a copy could define a conversion operator
to both the first copy and the original in
this way. </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Could you elaborate?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a
conversion operator would be disabled if the
copy has added new attributes with respect
to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Why?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Why do
you introduce this restriction? (on
template parameter numbers)<br>
</blockquote>
</div>
<div><br>
</div>
<div>No actually, you're right. I should lift
it. I thought initially that there wouldn't
be any reason to add more template
parameters, as they would only be needed to
satisfy the original class. But this is
definitely wrong. I'll change it, thanks.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">In **
above C has not yet defined as a copy<span
class=3D"m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Ill explain how I believe this example
should work. Since C has been declared but
not defined when parsing D, the compiler
will be allowed to assume that C is going to
be defined later as a type-copy of A. If
that does not happen, then the compiler will
give an error, either at the definition of C
or of D, explaining that D assumed that C
would have been a type-copy while it was
not. If C has added new attributes to its
declaration though D's definition would need
to take the new size of C into account
though. Not sure if this can be done or if
it should result in an error.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't know compiler writers would like to look
ahead. I believe that C should be forward declared as a
copy.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I
believe this interdependent case introduce
a lot of complexity. We would need a good
use case to introduce it on the standard.<spa=
n
class=3D"m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></blockquote>
<br>
</div>
<div>A very simple example would be copying of
inherited classes, both base and derived.
Without a way to do this that just cannot be
done. This can be important if one does not
want that the derived type and its type-copy
are allowed to be converted to the same
base. This is a strong reason, I believe,
otherwise strong-typing in that case just
lost some power in keeping original and
type-copy apart.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I will need a concrete example of when a complete
hierarchy must be "duplicated". I'm not saying there are
no cases, just I have no one in my head.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I
believe that this cannot be optional as in
a lot of cases we need to modify/restrict
the base type interface.<br>
</blockquote>
<br>
</div>
<div>I have actually removed this in my newest
revision. I believe that ground-up building
of types is the better way to go (as is
normally done in inheritance). Having the
power to completely alter the original type,
possibly to a point where there was not even
much in common between the original and the
type-copy, is not worth it. This is a
personal opinion, but I believe doing so can
prevent some very complex and ugly code
smells, at a not incredible cost.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> We need to solve concrete problems. The 1st use
case I have for strongly types is to reduce the interface
provided by the underlying type and to adapt the functions
signatures to the new class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>Could you give a concrete example of
this kind of problems?<br>
</div>
</blockquote>
<div>
<div style=3D"margin-left:40px"><span
class=3D"m_2667955782052143795m_-5826156030=
849956333gmail-im"></span></div>
<br>
</div>
<div>Suppose<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { re=
turn x * 2; }<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x=
) { return foo(x)
* 4.0; }<br>
};<br>
</div>
<div><br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int foo(int) =3D delete;<=
br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // bar cannot compile any=
more<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Where is the problem? struct B will not compile.
That's all.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct C : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(int x) { retur=
n x * 2; }<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // ambiguous definition<b=
r>
};<br>
</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are not modifying here, but adding ;-). You
can say it is ambiguous, but we have this case with
inheritance (<a moz-do-not-send=3D"true"
class=3D"m_2667955782052143795moz-txt-link-freetext"
href=3D"http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl=
"
target=3D"_blank">http://melpon.org/wandbox/<wbr>permlink/f=
9mRtE9n5mA9RPpl</a>)<span
class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct D : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(double x) { re=
turn x * 3;
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // Changes meaning of bar
underhandedly with no warning<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't see a problem here as D is a copy of A and
then we are defining its meaning.<br>
You said that it should be as simple as if defined the
class by hand.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>I suppose even more dangerous and complex
cases could be devised.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> We will need some real examples to see how
dangerous they are ;-)<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">While
this is inline with your approach, this
merits some explanations as the operators
are no members. Shouldn't the operators of
UDT classes meritt to be inherited as
well?<br>
</blockquote>
<div><br>
</div>
<div>I've removed primitive type support
also for this reason. They are not
currently treated as classes by C++, and
so I think I shouldn't either. Instead my
approach is now constructive. If one
needed aliases for primitive types, one
could create a single header of wrappers
in the form<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>class SimpleWrapper {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 public:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
SimpleWrapper(T t) : t_(t) {}<br>
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
T t_;<br>
</div>
<div>};<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>struct SimpleWrapperWithSum : using
SimpleWrapper<T> {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 SimpleWrapperWithSum
operator+(const SimpleWrapperWithSum &
other) { return t_ + other.t_; }<br>
</div>
<div>};<br>
<br>
</div>
<div>And so on. It would only be needed
once, and then users could simply copy the
versions with the operators they need to
use. It's not incredibly pretty and it
does have some limitations, but it works,
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe it is worth mentioning it in the
proposal. My TBoost.Opaque library implements something
like that. I will start a new thread to talk about the
TBoost.Opaque library approach. If I need a library
solution for builtin types, why this library solution will
not work for classes, what will be the added value of the
language solution?<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>and in any case even in p0109r0 one
would need to remove all unneeded
operators, so work would need to be done
anyway. <br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> No p0109r0 doesn't define any operation by default
(except conversions). The user needs to add whatever is
needed, maybe using the default trampoline
implementation). Well this is how I understand it.<span
class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>I believed that there where no
implicit conversions on your proposals.
How (*this) is converted to an int?<br>
<br>
What would be the result type of x
below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span
class=3D"m_2667955782052143795m_-58261560=
30849956333gmail-im"></span><br>
</div>
</blockquote>
<div>
<blockquote><span
class=3D"m_2667955782052143795m_-58261560=
30849956333gmail-im"></span></blockquote>
Yeah, this was a weird syntax, I thought
it could be a simple way to represent
conversion to the underlying primitive
type.<br>
<br>
The type of the operation would be Id,
yes. I believe that to be the only
intuitive result that makes sense, unless
an explicit operator+ that does a
conversion has been defined somewhere. If
a cast is needed, one needs to cast. I
don't see a reason to change that for
strong typedefs, otherwise the language
would be inconsistent IMO.<br>
<br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Why
this restriction is needed or desirable.<sp=
an
class=3D"m_2667955782052143795m_-5826156030849956333gmail-im"> (w.r.t.
final in type-copies of primitive
types)<br>
</span></blockquote>
<div><br>
</div>
<div>It is not. But I believe that if one
needs to do something, it has to be in
line with the rest of the language. If a
strong typedef of a primitive type is
needed, it would still need to follow
the rules of primitive types. </div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> It depends. If a strong type is able to define new
members it is not anymore a builtin and becomes for me a
class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>As primitive types are not
inheritable, I believe neither should
the strong typedefs. Maybe this is a
wrong position, I don't know (since
primitive typedefs are not inheritable
due to C compatibilities IIUC), but I
believe that having consistency is still
useful for a proposal. Otherwise one
needs to always learn a million
exceptions to each rule, and that I
don't like, where it can be avoided. In
any case, these are my opinions, but if
there is strong consensus to change how
the proposal works I have no problem in
modifying it.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You need to justify your decisions on a rationale
section. But as you have removed builtin types as base
types this is not needed anymore. You will need to justify
why builtin are not supported :(=C2=A0 <br>
<span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Exampl=
e
of where this can be useful welcome.<br>
</blockquote>
<div><br>
</div>
<div>I must admit I didn't really think
about this, I just thought they could
be nice to have. Maybe they would be
useless. I just considered that
sometimes the ingenuity of how people
use tools always seem to surprise, so
why not. Maybe in order to SFINAE the
generation of conversion operators to
classes, given that they are copies of
the original? Something like<br>
<br>
</div>
<div>struct Copy : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 template <=
typename T, /*
enable_if_t<is_copy_of_v<T,
A>>> */><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 operator T =
=3D default;<br>
</div>
<div>};<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Features must be added to solve concrete problems.<br=
>
<br>
I suggest you to work on the motivation section with real
concrete examples.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">How
other type traits behave for the
copied class (see p0109r0)?<br>
</blockquote>
<br>
</div>
<div>All other type traits behave as if
the class had been implemented by
hand, and is separate from the
original. so is_same would return
false, for example. It seems that
p0109r0 thinks the same way. The only
difference is that sizeof may be
different, since in my proposal one
could add additional attributes to the
type-copied class. (There's no
examples in the old version, I've
added them on GitHub though).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I agree for is_same of course. I was wondering for
other traits that could have been specialized for the base
class. I suspect the answer is that the user would need to
specialize the new type again.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Thanks again for your feedback.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are welcome,<br>
Vicente<br>
<br>
</div>
<span class=3D"">
-- <br>
You received this message because you are subscribed to a
topic in the Google Groups "ISO C++ Standard - Future
Proposals" group.<br>
To unsubscribe from this topic, visit <a
moz-do-not-send=3D"true"
href=3D"https://groups.google.com/a/isocpp.org/d/topic/std-proposals/gkJUVn=
L-Fmg/unsubscribe"
target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.o=
rg/d/topic/std-<wbr>proposals/gkJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an
email to <a moz-do-not-send=3D"true"
href=3D"mailto:std-proposals+unsubscribe@isocpp.org"
target=3D"_blank">std-proposals+unsubscribe@<wbr>isocpp.org=
</a>.<br>
To post to this group, send email to <a
moz-do-not-send=3D"true"
href=3D"mailto:std-proposals@isocpp.org" target=3D"_blank">=
std-proposals@isocpp.org</a>.<br>
</span>
To view this discussion on the web visit <a
moz-do-not-send=3D"true"
href=3D"https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a571=
16-c65b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.fr?utm_medium=3Demail&utm_sour=
ce=3Dfooter"
target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org=
/d/msgid/std-<wbr>proposals/f4a57116-c65b-94f4-<wbr>51f2-e5cf8b4ff3ca%40wan=
adoo.fr</a><wbr>.<br>
</blockquote>
</div>
<br>
</div>
-- <br>
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it,
send an email to <a moz-do-not-send=3D"true"
href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposals+=
unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a moz-do-not-send=3D"true"
href=3D"mailto:std-proposals@isocpp.org">std-proposals@isocpp.org</=
a>.<br>
To view this discussion on the web visit <a
moz-do-not-send=3D"true"
href=3D"https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%=
3D%2BtVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com?utm_me=
dium=3Demail&utm_source=3Dfooter">https://groups.google.com/a/isocpp.or=
g/d/msgid/std-proposals/CAHfn%3D%2BtVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGy=
WzZMgg%40mail.gmail.com</a>.<br>
</blockquote>
<p><br>
</p>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ef8190c7-f46f-cf76-7e45-2114a84eae27%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ef8190c7-f46f-cf76-7e45-2114a84eae27=
%40wanadoo.fr</a>.<br />
--------------AEDADE077498BC8C9124C5AA--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Sun, 1 Jan 2017 18:26:16 +0100
Raw View
--94eb2c03c7908d1bfd05450bbbd4
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vicente,
Eugenio, please, preserve some additional context in your responses.
>
Sorry, I'll try to be more careful.
I really understand this feeling. However, consider this: at which point is
>> something a strong typedef of something else, and when is it a new class=
?
>> Is the mechanism we want to introduce simply a way to declare a new clas=
s,
>> using another as a starting point and completely editable, or we want th=
ere
>> to be some kind of association (even if it was only on a logical level)
>> between the two things
>>
> I see that you want to add a new mechanism to define a new class using
> another class as starting point, but I would not name this a strong type
> proposal, even if it can be used to build some strong types. Whether this
> is useful by itself needs more motivation and concrete real examples.
>
I don't understand. Even what you want from a strong typing proposal is
still to define a new class from an old class. The only difference I see
between what we are talking about is that I don't think editing the old
class is useful enough compared to the downsides, and you don't.
Why would you have copied A in the first place then, rather than create a
>> new class?
>>
> Add just N bazN() functions to A and you will see why it is interesting t=
o
> modify B because B doesn't want to provide the foo function, but all the
> bazN functions.
I do see that. The problem is that once a feature is out you don't get to
tell people how to use it. And people WILL misuse having the power to alter
everything every time. I don't believe it is possible to assume that this
won't happen. Base on my personal experience, this will happen a lot, and
it will be bad.
Note that inheritance allows you to make a member not accessible.
> struct A {
> int foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> struct B : A {
> private:
> double bar(double x);
> };
I assume that you wanted to use public inheritance. With private
inheritance being an equivalent of encapsulation, the assertion would not
be interesting, since wrapping of course removes access to the encapsulated
data. With public inheritance, you did not make that member not accessible.
It is still so, you have just hidden it.
B b;
b.A::bar(5);
There is a difference. In addition, I don't believe that two wrongs make a
right. Making a feature that can be potentially abused in the worst ways is
not wise, I think.
One of the problems of your proposal is that the copied class has access to
>> the private members, which is more subject to changes. I believe that th=
e
>> copied class should only have access to public members.
>
>
> If one creates a new class, and private members cannot be accessed, there
> will not be any way to touch them to do anything else aside from the
> original interface.
>
> Right.
>
> This is also compounded by the fact that all old methods accepting the
> original class won't work on the new class (creating an operator Base()
> should be an exception for certain use-cases, it should not be necessary =
to
> do so).
>
> The Base conversion can be protected or private. The trampoline would tak=
e
> care of this conversions.
>
> How are you going to print a copy?
>
> Hmm, using the public interface or don't.
>
> How can you convert in a custom way to the original class?
>
> I don't see the use case. Maybe you have one.
>
> How are you going to implement additional and useful methods without
> access to privates?
>
> If we need to access to private I believe it is worth creating a new
> class.
If I understand correctly, you want to be able to create a copy of another
class, with the ability to alter and access its public interface only. What
happens when you delete a public method used by a private method? What
happens when you delete a public attribute used in private code? What
happens to protected code - if not accessible you basically make
inheritance useless on it? If in all these cases your answer is "the
program will fail to compile, just copy the class by hand" then I think the
feature would be severely limited in what it could actually do.
I feel that what you are proposing is basically a fast way to create PIMPL
wrappers. If I understand correctly, you want to hide the original
completely, and just be offered an easy way to bring back some of its
interface (via trampolines) to its "wrapper", which would be the strong
typedef. Possibly adding more public methods only using the public
interface, which could be done just the same with non-member methods. The
end result is a class that cannot be extended in any meaningful way using
any of the normal C++ facilities, since every juicy bit is hidden. Applying
inheritance to it would require manual exposure of all methods, with the
limitations we have already discussed. Applying strong-typing again to a
strong-typed class would be useless as access to internals would be the
same, aside from possibly adding more data (if needed) in the public
attributes, since only those are editable. This would also prevent
encapsulation of new data. If not, it would just mean that the feature
wouldn't be used in a composable way.
My own idea is to be able to extend an already existing class into a new
class. I may not have 100% use cases for all things I'm proposing, but that
is simply because I can't write in advance all possible programs with the
feature. I just feel (maybe feeling is not enough, but opinions are also
made of these unfortunately) that if a new feature has to be introduced it
should at least try to play ball with the rest of the language. The more it
does, the more it can be used in any weird case that may come up. One of
the most beautiful things about C++ is that there's pretty much always a
way to do something, exactly because the language is flexible and its parts
can be combined in many possible ways. A feature that creates a
non-extendable object is like a dead-end.
What I mean is that these wrappers should be part of the proposal and show
> how the your copy class reach to make concrete and real opaque types as e=
..g
> the energy example in P0109.
>
But wrappers can be made in a separate library. Why should they be included
in the proposal? As long as the proposal allows them, a library only needs
to be made once (and if not needed by someone, not used).
> You see that in order to have a custom type, still many things must be
> written. So what's the difference between creating copyable wrappers (usi=
ng
> normal C++ rules), and creating a number of such interfaces (having to
> learn and teach how protected/public/private work in a new context)? I
> don't see what the difference would be. Why do you feel that wrappers on
> primitive types are not enough?
>
> Yes, the new opaque type must define all the available functions. Note
> that p0109 provides conversions and the possibility to request the compil=
er
> to generate the default trampolines. This is much sorter than defining th=
em
> using the current C++ language. Implicit conversions (public) allow to us=
e
> the new opaque type where the underlying type was expected.
>
> I would prefer the opaque type proposal to go even further (or an
> independent proposal) and be able to introduce groups of trampolines as I
> did on my Opaque library with the combined mixins. However I have no
> concrete proposal at the language level.
>
But I have made you an example with wrappers, which you also agreed is
similar to what your library currently does. So what is wrong with that
approach?
struct A {
> A append(A const&);
> };
>
> struct B : using A {};
>
> What will be the type of x
>
> B b1, b2;
> auto x =3D b1.append(b2);
>
> IIUC your proposal, the append function will be copied replacing any
> occurrence of A by B, so it is as if B was declared
>
> struct B {
> B append(B const&);
> };
>
> Am I missing something? (***)
>
> Or would B equivalent to
>
> struct B {
> A append(B const&);
> };
>
> or to
>
> struct B {
> A append(A const&);
> };
>
> I'm wondering now if the copied class could add at all new non-static dat=
a
> members. Otherwise I don't see how the duplication of such function can b=
e
> done. I suspect that p0109 doesn't allow to add new data.
> Then, if the user wants to add more data, it should first duplicate the
> class and then inherit from the duplicated class to add more data.
>
No, you understood correctly, the end result would be
struct B {
B append(B const&);
};
Forcing the user to inherit to add more data adds inheritance, which means
that types are now implicitly convertible (to at least a common base). I
don't think this is desirable. I think strong typing should work on its own=
..
In some sense creating a new foo overload using the type-copy. However, I
> believe this would be a pretty big change.
>
> I believed this was already part of your proposal. (***)
>
Mhh, now that you put it this way. I thought about only doing this for
classes. While the mechanism for free functions would be the same (that's
what I mean by strong-typedef of a function, see below), the scope would be
wider. One only works for classes, the other on all free functions. I don't
know, maybe dividing them makes no sense. I'd love to hear what you think
about this.
> As this is outside of the scope of my proposal, I did not include this.
> And so, I cannot add to my proposal the conversion of friend and non-memb=
er
> function when creating a copy-type. If this could be included, there woul=
d
> be no problem for that.
>
> Sorry, I don't know yet what are type-aliases of methods.
>
I'll try to explain myself better. A strong typedef of a function would be
taking that function and replacing one or more types within it to others.
You could say that when you do:
template <typename T>
void foo(T);
then foo<int> and foo<double> are "strong typedefs" of each other, in some
sense. If one were allowed to do this to existing code, one could do
something like
void foo(int);
void foo(double) : using foo(int);
to use an analogous syntax to the one in my proposal. Not sure if this is
clearer, let me know.
> For example, consider
>
> struct A {};
> struct B : using A {
> operator A() =3D default;
> };
> struct C : using B {
> operator B() =3D default;
> operator A() =3D default;
> };
>
> Just an idea.
>
> I'm lost.
>
What I mean is, if B is a strong typedef of A, then we can default its
conversion operator to A, right? But then, if C is a type-copy of B, then
we can default its conversion operator to both B (since it's its
type-copy), and also to A (since C is a type-copy of a type-copy).
Is it really wise to allow the compiler to be able to default convert B to
> A?
>
> I would say, yes. The question p0109 raise is whether the user wants it.
>
I'm not sure, however to me there's no difference either way.
Maybe. I thought that inherited classes are also declared without
> mentioning that they inherit, so I though that the same should hold for
> copies.
>
> Maybe, but the C++ standard doesn't have constrains on whether the class
> is derived from another class.
>
True. I'll try to think about this a bit more. Maybe we could simply lift
the restriction and let the user do what he/she wants? (so also use classes
that are not necessarily copies of the originals, as long as their
interface is compatible to what it needs to be)
> That's true, and that's mostly what I don't like about giving the ability
> to modify copied existing methods. It is definitely non-obvious that this
> is happening. If you make a mistake, it will take a long time to figure o=
ut
> that you involuntarily modified the behavior of the original class. That'=
s
> bad in my book.
>
> Maybe you need something like override to state clearly that you want to
> redefine the inherited behavior.
>
Unfortunately there would be nothing to override, as you are adding a new
overload completely separate to the old one. Both would still be usable and
work, nothing is being redefined. Simply the old function would get linked
against the new implementation. There's nothing that the compiler could do
to prevent this.
Best,
Eugenio
On Sun, Jan 1, 2017 at 4:56 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 31/12/2016 =C3=A0 19:39, Eugenio Bargiacchi a =C3=A9crit :
>
> Eugenio, please, preserve some additional context in your responses.
>
> From you responses, I believe that I have not understood your proposal.
> See below (***)
>
> To be honest, I will vote against this proposal if we can not modify and
>> delete existing functionality. When I copy/paste a class I can change
>> things and remove others.
>>
>
> I really understand this feeling. However, consider this: at which point
> is something a strong typedef of something else, and when is it a new
> class? Is the mechanism we want to introduce simply a way to declare a ne=
w
> class, using another as a starting point and completely editable, or we
> want there to be some kind of association (even if it was only on a logic=
al
> level) between the two things?
>
> I see that you want to add a new mechanism to define a new class using
> another class as starting point, but I would not name this a strong type
> proposal, even if it can be used to build some strong types. Whether this
> is useful by itself needs more motivation and concrete real examples.
>
>
> A mechanism that freely allows you to edit classes wouldn't be a strong
> typedef, in my opinion. Consider:
>
> struct A {
> void foo();
> };
>
> struct B : using A {
> void foo() =3D delete;
> void bar();
> };
>
> Why would you have copied A in the first place then, rather than create a
> new class?
>
> Add just N bazN() functions to A and you will see why it is interesting t=
o
> modify B because B doesn't want to provide the foo function, but all the
> bazN functions.
>
> If instead you could say "copies can only add" then when you find a class
> declared as a copy you can easily reason about it. Think about a long
> chains of copies:
>
> struct A { /* .... */ };
> struct B : using A { /* .... */ };
> struct C : using B { /* .... */ };
> struct D : using C { /* .... */ };
> struct E : using D { /* .... */ };
>
> All these maybe in different files, in different places. Then what is E?
> If you are allowed to remove and change things, then you'd have to start =
at
> A and manually keep track of which things are deleted, maybe re-added
> later, maybe modified. It would be really hard to know exactly what E is.
> While if you're allowed to only increment, it would be much easier to kno=
w
> that - or at least on par with inheritance. If you can find it once in th=
e
> chain, then it exists. I believe this is an important fact that must be
> considered when thinking about what features we want in strong typing.
>
> Note that inheritance allows you to make a member not accessible.
> struct A {
> int foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> struct B : A {
> private:
> double bar(double x);
> };
>
>
> One of the problems of your proposal is that the copied class has access
>> to the private members, which is more subject to changes. I believe that
>> the copied class should only have access to public members.
>
>
> If one creates a new class, and private members cannot be accessed, there
> will not be any way to touch them to do anything else aside from the
> original interface.
>
> Right.
>
> This is also compounded by the fact that all old methods accepting the
> original class won't work on the new class (creating an operator Base()
> should be an exception for certain use-cases, it should not be necessary =
to
> do so).
>
> The Base conversion can be protected or private. The trampoline would tak=
e
> care of this conversions.
>
> How are you going to print a copy?
>
> Hmm, using the public interface or don't.
>
> How can you convert in a custom way to the original class?
>
> I don't see the use case. Maybe you have one.
>
> How are you going to implement additional and useful methods without
> access to privates?
>
> If we need to access to private I believe it is worth creating a new
> class.
>
>
> Again, I will vote against this proposal if it doesn't provides a solutio=
n
>> for builtin types, as this is IMHO one of the most appealing use cases.
>>
>
> A solution exists, and is the one that already exists when one wants to
> limit operations done on existing types: build a wrapper. The difference =
is
> that before a completely new wrapper had to be built from scratch for eac=
h
> new needed primitive alias, depending on the required operations, with th=
is
> proposal they become easily composable, so once done it never has to be
> done again, and adding new types becomes a one-liner for the user.
>
> What I mean is that these wrappers should be part of the proposal and sho=
w
> how the your copy class reach to make concrete and real opaque types as e=
..g
> the energy example in P0109.
>
>
> Consider this against what p0109r0 does:
>
> template <class T =3D double>
> using energy =3D protected double {
> energy operator+ (energy , energy) =3D default;
> energy& operator*=3D(energy&, T ) =3D default;
> energy operator*(energy , energy) =3D delete;
> energy operator*(energy , T ) =3D default;
> energy operator*(T , energy) =3D default;
> };
>
> You see that in order to have a custom type, still many things must be
> written. So what's the difference between creating copyable wrappers (usi=
ng
> normal C++ rules), and creating a number of such interfaces (having to
> learn and teach how protected/public/private work in a new context)? I
> don't see what the difference would be. Why do you feel that wrappers on
> primitive types are not enough?
>
> Yes, the new opaque type must define all the available functions. Note
> that p0109 provides conversions and the possibility to request the compil=
er
> to generate the default trampolines. This is much sorter than defining th=
em
> using the current C++ language. Implicit conversions (public) allow to us=
e
> the new opaque type where the underlying type was expected.
>
> I would prefer the opaque type proposal to go even further (or an
> independent proposal) and be able to introduce groups of trampolines as I
> did on my Opaque library with the combined mixins. However I have no
> concrete proposal at the language level.
>
>
> Your proposal has already this issue as you copy the whole class, and so
>> you replace every occurrence of the base class with the new class.
>>
>
> I'm not sure what you mean. In my proposal, the copy is a new class, and
> so it is always obvious what an assignment operator is going to result in=
..
> In p0109r0 this is more complex because depending on the access specifier
> different default conversion operators are defined. Not sure what you mea=
n
> when you mention the replacement that happens, and what the issue is.
>
>
>
> struct A {
> A append(A const&);
> };
>
> struct B : using A {};
>
> What will be the type of x
>
> B b1, b2;
> auto x =3D b1.append(b2);
>
> IIUC your proposal, the append function will be copied replacing any
> occurrence of A by B, so it is as if B was declared
>
> struct B {
> B append(B const&);
> };
>
> Am I missing something? (***)
>
> Or would B equivalent to
>
> struct B {
> A append(B const&);
> };
>
> or to
>
> struct B {
> A append(A const&);
> };
>
> I'm wondering now if the copied class could add at all new non-static dat=
a
> members. Otherwise I don't see how the duplication of such function can b=
e
> done. I suspect that p0109 doesn't allow to add new data.
> Then, if the user wants to add more data, it should first duplicate the
> class and then inherit from the duplicated class to add more data.
>
>
> I don't know what do you mean by type-aliases of methods. Could you
>> elaborate?
>>
>
> Yes. So consider this:
>
> struct A {
> friend void foo(A&);
> };
>
> struct B : using A {};
>
> To me the only way to allow B to also have the friend declaration is if w=
e
> could do the following transformation:
>
> void foo(A&) ----> void foo(B&)
>
> Right.
>
>
> In some sense creating a new foo overload using the type-copy. However, I
> believe this would be a pretty big change.
>
> I believed this was already part of your proposal. (***)
>
> If such a thing was allowed, then why stop at copies? Why not being able
> to define
>
> void foo(A&) ----> void foo(C&)
>
> or even
>
> void foo(A&) ----> template<typename T> void foo(T&);
>
> As this is outside of the scope of my proposal, I did not include this.
> And so, I cannot add to my proposal the conversion of friend and non-memb=
er
> function when creating a copy-type. If this could be included, there woul=
d
> be no problem for that.
>
> Sorry, I don't know yet what are type-aliases of methods.
>
>
> Could you elaborate? (on recursive conversion operator)
>>
>
> For example, consider
>
> struct A {};
> struct B : using A {
> operator A() =3D default;
> };
> struct C : using B {
> operator B() =3D default;
> operator A() =3D default;
> };
>
> Just an idea.
>
> I'm lost.
>
>
> However, this default way to define a conversion operator would be
>> disabled if the copy has added new attributes with respect to its origin=
al
>> class.
>>
>> Why?
>>
>
> I think that at that point the two classes diverged enough that the
> compiler cannot assume they can be converted freely? If I have:
>
> struct A { int x; };
> struct B : using A { int y; };
>
> Is it really wise to allow the compiler to be able to default convert B t=
o
> A?
>
> I would say, yes. The question p0109 raise is whether the user wants it.
>
> If they were the same, ok, but maybe at that point the user should be
> forced to provide a conversion operator, no?
>
> If the user decides to provide the default implementation I don't see
> where the problem is.
>
> operator Base() =3D default;
>
> The compiler know how to do the conversion.
>
>
> I don't know compiler writers would like to look ahead. I believe that C
>> should be forward declared as a copy.
>>
>
> Maybe. I thought that inherited classes are also declared without
> mentioning that they inherit, so I though that the same should hold for
> copies.
>
> Maybe, but the C++ standard doesn't have constrains on whether the class
> is derived from another class.
>
>
> I will need a concrete example of when a complete hierarchy must be
>> "duplicated". I'm not saying there are no cases, just I have no one in m=
y
>> head.
>>
>
> I'll try to add these on the concrete examples.
>
> You are not modifying here, but adding ;-). You can say it is ambiguous,
>> but we have this case with inheritance (http://melpon.org/wandbox/per
>> mlink/f9mRtE9n5mA9RPpl)
>>
>
> Not quite, the resulting copied class would be equivalent to
>
> struct C {
> int foo(int x) { return x * 2; }
> double foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> which is illegal, since you cannot overload on return type. Keep in mind
> that there is no "layer" between the original class and what gets added t=
o
> the copy.
>
> You are right. I missed that all the function are copied. In this case,
> either a function is not copied when there is an added function with the
> same overloaded signature or the program is ill formed.
>
>
> I don't see a problem here as D is a copy of A and then we are defining
>> its meaning.
>> You said that it should be as simple as if defined the class by hand.
>>
>
> That's true, and that's mostly what I don't like about giving the ability
> to modify copied existing methods. It is definitely non-obvious that this
> is happening. If you make a mistake, it will take a long time to figure o=
ut
> that you involuntarily modified the behavior of the original class. That'=
s
> bad in my book.
>
> Maybe you need something like override to state clearly that you want to
> redefine the inherited behavior.
>
>
> I believe it is worth mentioning it in the proposal. My TBoost.Opaque
>> library implements something like that. I will start a new thread to tal=
k
>> about the TBoost.Opaque library approach. If I need a library solution f=
or
>> builtin types, why this library solution will not work for classes, what
>> will be the added value of the language solution?
>>
>
> I believe that wrapper types are just as good as primitive types. This is
> also how it's always been in C++. The main problem was simply that doing
> this over and over and over was incredibly unwieldy. I don't believe that
> the reason why the older, in-C++ approaches didn't work is that they were
> creating wrappers rather than "primitive type aliases". This proposal
> eliminates the need for repetition as once done, it is done forever. A
> library like boost can pre-produce often used primitive types wrappers on=
ce
> in a single header, and be done forever.
>
> No p0109r0 doesn't define any operation by default (except conversions).
>> The user needs to add whatever is needed, maybe using the default
>> trampoline implementation). Well this is how I understand it.
>>
>
> From the proposal: "Since all member functions of the underlying type are
> known to the compiler, we can take advantage of this and therefore propos=
e
> that the compiler, by default, generate default versions of these
> trampolines."
>
> I interpret this as the compiler could generate them by default, once the
> user has requested it using the =3D default syntax. I agree the proposal
> doesn't contain examples where this is clear enough.
>
>
>
> Vicente
>
>
> On Sat, Dec 31, 2016 at 6:15 PM, Vicente J. Botet Escriba <
> vicente.botet@wanadoo.fr> wrote:
>
>> Le 31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit :
>>
>> Dear Vincente,
>>
>> Thank you for your very in-depth review. I've updated the proposal using
>> already received comments from this thread, so some things have changed,
>> but it's still alright to receive comments on this version. I'll explain
>> below how it has changed when answering to your comments.
>>
>> IIUC, every occurrence of the base type in the definition of the base
>>> type is replaced by the new type. This is one of the options described =
in
>>> Opaque proposal (see The return type issue). Why the other alternatives
>>> have less sens?
>>>
>>
>> There are many differences between my proposal and the Opaque proposal. =
I
>> believe that the main ones that this proposal brings are:
>>
>> - Where possible, do not introduce new meanings or rules to the language=
..
>> The type-copied class should behave as closely as possible to a class th=
e
>> user has implemented by hand. This should make very easy to understand h=
ow
>> the feature works, without the need to grasp many new concepts.
>> - I have removed the option to modify and remove existing functionality
>> from the class that is being copied. While I believe that this can be
>> useful, it introduces too much complexity in my opinion now. If this is
>> allowed, you basically have to create a system where you are allowed to
>> completely rewrite an existing class starting from another, since you ma=
y
>> want to copy or remove or change anything that was previously present. T=
his
>> I believe can both make the proposal unnecessary complicated, and can ma=
ke
>> the code very hard to follow, as at each new strong-typedef step (since =
a
>> type could be copied, and the copy copied again and so on) anything coul=
d
>> happen. I now believe that an incremental-only strategy (similar to
>> inheritance) can still be both useful and sufficient for most cases. Whe=
re
>> it is not, simple implementations by hand of basic functionality, extend=
ed
>> then via the type-copy mechanism should result in clear, reusable code
>> which still requires little maintenance.
>>
>> To be honest, I will vote against this proposal if we can not modify and
>> delete existing functionality. When I copy/paste a class I can change
>> things and remove others.
>>
>>
>> The word duplicating and wrapping don't match. The proposed approach
>>> doesn't wraps the underlying type, except maybe for builtin types.
>>>
>>
>> Right, I'll fix it, thanks.
>>
>> I believe the proposal needs to add some concrete examples as use cases
>>>
>>
>> This makes sense, I'll worn ok an additional section where I try to show
>> some concrete examples.
>>
>> The best will be to add them in the motivation section showing how the
>> new feature is used instead of some flat code.
>>
>>
>> If the base class change, the strong types depending on it could need
>>> maintenance also, isn't it?
>>>
>>
>> True, however wrapper methods have to be fixed 100% of the time, while a
>> type-copied class may not need this. It's the same as if one modified a
>> base class in inheritance - you don't have to necessarily update all the
>> code that depends on it right away.
>>
>> One of the problems of your proposal is that the copied class has access
>> to the private members, which is more subject to changes. I believe that
>> the copied class should only have access to public members.
>>
>>
>> In addition to these basic techniques, there are other library solution,
>>> as e.g. using CRTP that might merit to be mentioned.
>>> See [TBoost.Opaque] for a possible implementation.
>>>
>>
>> I'll add a mention to CRTP. I'll give a look at the boost link, thanks!
>>
>> Please add http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p010
>>> 9r0.pdf to this list.
>>>
>>
>> Thanks, I must have missed it.
>>
>> What is wrong for you with p0109r0 approach?
>>> What we could have with your approach that we cannot have with p0109r0?
>>> What we could have with p0109r0 that we cannot have with your approach?
>>>
>>> IIUC, p0109r0 opaque types don't introduce any operations by default
>>> other than conversions and your proposal introduce all members but no
>>> friends
>>>
>>
>> Personally, I don't think there's anything "wrong" with p0109r0. The ide=
a
>> for this proposal came to me before I knew the alternatives, but since C=
++
>> still does not have strong typedefs I thought I might as well propose an
>> alternative approach, which could possibly garner more interest.
>>
>> I believe my approach is simpler to read and more intuitive - especially
>> when creating strong aliases of very complex types, but that can definit=
ely
>> be bias. It can be applied to hierarchies of classes, since it allows
>> type-copying interdependent classes, which I believe is very important. =
It
>> is very easy to use with templates and specializations, which potentiall=
y
>> gives it a lot of power and very many potential uses. It is easily
>> composable, as in copying a copy is very easy and indeed expected in my
>> view for the feature.
>>
>> You will need to show how all this arguments applies on concrete example=
s
>> and how p0109r0 could do the same thing.
>>
>>
>> With p0109r0 there's more flexibility to alter a type. The additional
>> flexibility allows it to take on more tasks, as in type-copying friends,
>> since default ways to convert to the original types exist. It is designe=
d
>> for primitive types first, while I have actually removed them in my last
>> iteration for a number of reasons (see below).
>>
>> Again, I will vote against this proposal if it doesn't provides a
>> solution for builtin types, as this is IMHO one of the most appealing us=
e
>> cases.
>>
>> The additional flexibility however comes at a cost, as you mention the
>> return type issue, which my proposal does not have.
>>
>> Your proposal has already this issue as you copy the whole class, and so
>> you replace every occurrence of the base class with the new class.
>>
>>
>> I don't introduce friends mostly because a feature to create type-aliase=
s
>> of methods does not currently exist,
>>
>> I don't know what do you mean by type-aliases of methods. Could you
>> elaborate?
>>
>> and I don't believe it is wise to add it to the scope of this proposal
>> since it would be another very large change. If such a feature existed,
>> however, adding friends to a type-copied class in my proposal would be
>> trivial, as simply strong typedefs of the needed functions could be crea=
ted
>> on the fly. The same could also be done for non-member functions if need=
ed,
>> but how that would work I have not thought about yet.
>>
>> Could you elaborate how type-aliases of methods would help here?
>>
>>
>> I find that conversions to/from the underlying type must be covered by
>>> the proposal. If we change the Base type we don't want to be forced to
>>> redefine the conversion operator.
>>> Maybe we need some kind of default conversion implementation
>>> operator Base() *=3D default*;
>>> or
>>> *explicit* operator Base() *=3D default*;
>>>
>>
>> I like this. I didn't add it to keep the number of features as low as
>> reasonably possible, but this is simple enough. This could also be used
>> recursively, as in a copy of a copy could define a conversion operator t=
o
>> both the first copy and the original in this way.
>>
>> Could you elaborate?
>>
>> However, this default way to define a conversion operator would be
>> disabled if the copy has added new attributes with respect to its origin=
al
>> class.
>>
>> Why?
>>
>>
>> Why do you introduce this restriction? (on template parameter numbers)
>>>
>>
>> No actually, you're right. I should lift it. I thought initially that
>> there wouldn't be any reason to add more template parameters, as they wo=
uld
>> only be needed to satisfy the original class. But this is definitely wro=
ng.
>> I'll change it, thanks.
>>
>> In ** above C has not yet defined as a copy
>>>
>>
>> Ill explain how I believe this example should work. Since C has been
>> declared but not defined when parsing D, the compiler will be allowed to
>> assume that C is going to be defined later as a type-copy of A. If that
>> does not happen, then the compiler will give an error, either at the
>> definition of C or of D, explaining that D assumed that C would have bee=
n a
>> type-copy while it was not. If C has added new attributes to its
>> declaration though D's definition would need to take the new size of C i=
nto
>> account though. Not sure if this can be done or if it should result in a=
n
>> error.
>>
>> I don't know compiler writers would like to look ahead. I believe that C
>> should be forward declared as a copy.
>>
>>
>> I believe this interdependent case introduce a lot of complexity. We
>>> would need a good use case to introduce it on the standard.
>>>
>>
>> A very simple example would be copying of inherited classes, both base
>> and derived. Without a way to do this that just cannot be done. This can=
be
>> important if one does not want that the derived type and its type-copy a=
re
>> allowed to be converted to the same base. This is a strong reason, I
>> believe, otherwise strong-typing in that case just lost some power in
>> keeping original and type-copy apart.
>>
>> I will need a concrete example of when a complete hierarchy must be
>> "duplicated". I'm not saying there are no cases, just I have no one in m=
y
>> head.
>>
>>
>> I believe that this cannot be optional as in a lot of cases we need to
>>> modify/restrict the base type interface.
>>>
>>
>> I have actually removed this in my newest revision. I believe that
>> ground-up building of types is the better way to go (as is normally done=
in
>> inheritance). Having the power to completely alter the original type,
>> possibly to a point where there was not even much in common between the
>> original and the type-copy, is not worth it. This is a personal opinion,
>> but I believe doing so can prevent some very complex and ugly code smell=
s,
>> at a not incredible cost.
>>
>> We need to solve concrete problems. The 1st use case I have for strongly
>> types is to reduce the interface provided by the underlying type and to
>> adapt the functions signatures to the new class.
>>
>>
>> Could you give a concrete example of this kind of problems?
>>>
>>
>> Suppose
>>
>> struct A {
>> int foo(int x) { return x * 2; }
>> double bar(double x) { return foo(x) * 4.0; }
>> };
>>
>> struct B : using A {
>> int foo(int) =3D delete;
>> // bar cannot compile anymore
>> };
>>
>> Where is the problem? struct B will not compile. That's all.
>>
>> struct C : using A {
>> double foo(int x) { return x * 2; }
>> // ambiguous definition
>> };
>>
>> You are not modifying here, but adding ;-). You can say it is ambiguous,
>> but we have this case with inheritance (http://melpon.org/wandbox/per
>> mlink/f9mRtE9n5mA9RPpl)
>>
>> struct D : using A {
>> double foo(double x) { return x * 3; }
>> // Changes meaning of bar underhandedly with no warning
>> };
>>
>> I don't see a problem here as D is a copy of A and then we are defining
>> its meaning.
>> You said that it should be as simple as if defined the class by hand.
>>
>> I suppose even more dangerous and complex cases could be devised.
>>
>> We will need some real examples to see how dangerous they are ;-)
>>
>>
>> While this is inline with your approach, this merits some explanations a=
s
>>> the operators are no members. Shouldn't the operators of UDT classes me=
ritt
>>> to be inherited as well?
>>>
>>
>> I've removed primitive type support also for this reason. They are not
>> currently treated as classes by C++, and so I think I shouldn't either.
>> Instead my approach is now constructive. If one needed aliases for
>> primitive types, one could create a single header of wrappers in the for=
m
>>
>> template <typename T>
>> class SimpleWrapper {
>> public:
>> SimpleWrapper(T t) : t_(t) {}
>>
>> private:
>> T t_;
>> };
>>
>> template <typename T>
>> struct SimpleWrapperWithSum : using SimpleWrapper<T> {
>> SimpleWrapperWithSum operator+(const SimpleWrapperWithSum & other) {
>> return t_ + other.t_; }
>> };
>>
>> And so on. It would only be needed once, and then users could simply cop=
y
>> the versions with the operators they need to use. It's not incredibly
>> pretty and it does have some limitations, but it works,
>>
>> I believe it is worth mentioning it in the proposal. My TBoost.Opaque
>> library implements something like that. I will start a new thread to tal=
k
>> about the TBoost.Opaque library approach. If I need a library solution f=
or
>> builtin types, why this library solution will not work for classes, what
>> will be the added value of the language solution?
>>
>> and in any case even in p0109r0 one would need to remove all unneeded
>> operators, so work would need to be done anyway.
>>
>> No p0109r0 doesn't define any operation by default (except conversions).
>> The user needs to add whatever is needed, maybe using the default
>> trampoline implementation). Well this is how I understand it.
>>
>>
>> I believed that there where no implicit conversions on your proposals.
>>> How (*this) is converted to an int?
>>>
>>> What would be the result type of x below?
>>>
>>> Id id(1);
>>> auto x =3D +id;
>>>
>>> I suspect that it would be Id.
>>>
>> Yeah, this was a weird syntax, I thought it could be a simple way to
>> represent conversion to the underlying primitive type.
>>
>> The type of the operation would be Id, yes. I believe that to be the onl=
y
>> intuitive result that makes sense, unless an explicit operator+ that doe=
s a
>> conversion has been defined somewhere. If a cast is needed, one needs to
>> cast. I don't see a reason to change that for strong typedefs, otherwise
>> the language would be inconsistent IMO.
>>
>> Why this restriction is needed or desirable. (w.r.t. final in
>>> type-copies of primitive types)
>>>
>>
>> It is not. But I believe that if one needs to do something, it has to be
>> in line with the rest of the language. If a strong typedef of a primitiv=
e
>> type is needed, it would still need to follow the rules of primitive typ=
es.
>>
>> It depends. If a strong type is able to define new members it is not
>> anymore a builtin and becomes for me a class.
>>
>> As primitive types are not inheritable, I believe neither should the
>> strong typedefs. Maybe this is a wrong position, I don't know (since
>> primitive typedefs are not inheritable due to C compatibilities IIUC), b=
ut
>> I believe that having consistency is still useful for a proposal. Otherw=
ise
>> one needs to always learn a million exceptions to each rule, and that I
>> don't like, where it can be avoided. In any case, these are my opinions,
>> but if there is strong consensus to change how the proposal works I have=
no
>> problem in modifying it.
>>
>> You need to justify your decisions on a rationale section. But as you
>> have removed builtin types as base types this is not needed anymore. You
>> will need to justify why builtin are not supported :(
>>
>>
>> Example of where this can be useful welcome.
>>>
>>
>> I must admit I didn't really think about this, I just thought they could
>> be nice to have. Maybe they would be useless. I just considered that
>> sometimes the ingenuity of how people use tools always seem to surprise,=
so
>> why not. Maybe in order to SFINAE the generation of conversion operators=
to
>> classes, given that they are copies of the original? Something like
>>
>> struct Copy : using A {
>> template <typename T, /* enable_if_t<is_copy_of_v<T, A>>> */>
>> operator T =3D default;
>> };
>>
>> Features must be added to solve concrete problems.
>>
>> I suggest you to work on the motivation section with real concrete
>> examples.
>>
>>
>> How other type traits behave for the copied class (see p0109r0)?
>>>
>>
>> All other type traits behave as if the class had been implemented by
>> hand, and is separate from the original. so is_same would return false, =
for
>> example. It seems that p0109r0 thinks the same way. The only difference =
is
>> that sizeof may be different, since in my proposal one could add additio=
nal
>> attributes to the type-copied class. (There's no examples in the old
>> version, I've added them on GitHub though).
>>
>> I agree for is_same of course. I was wondering for other traits that
>> could have been specialized for the base class. I suspect the answer is
>> that the user would need to specialize the new type again.
>>
>>
>> Thanks again for your feedback.
>>
>> You are welcome,
>> Vicente
>>
>> --
>> 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/is
>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-
>> e5cf8b4ff3ca%40wanadoo.fr
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a57116-c=
65b-94f4-51f2-e5cf8b4ff3ca%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoo=
ter>
>> .
>>
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtVBKZOMtpURNBDCEJijFL_J5s%
> 2BROrLwJfkRgGyWzZMgg%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
tVBKZOMtpURNBDCEJijFL_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com?utm_medium=
=3Demail&utm_source=3Dfooter>
> .
>
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/ef8190c7-f46f-cf76-
> 7e45-2114a84eae27%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ef8190c7-f4=
6f-cf76-7e45-2114a84eae27%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BtEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezP=
DzS3fAw%40mail.gmail.com.
--94eb2c03c7908d1bfd05450bbbd4
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Dear Vicente,<br><br><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex">Eugenio, please, preserve some additional context in your
responses.<br></blockquote><div><br></div><div>Sorry, I'll try to=
be more careful. <br></div><br><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-lef=
t:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gma=
il-im"><div dir=3D"ltr"><div>I really understand this feeling. However, con=
sider this:
at which point is something a strong typedef of something
else, and when is it a new class? Is the mechanism we want to
introduce simply a way to declare a new class, using another
as a starting point and completely editable, or we want there
to be some kind of association (even if it was only on a
logical level) between the two things</div></div></span></blockqu=
ote><span class=3D"gmail-im"><div dir=3D"ltr"><div>
</div></div></span><blockquote><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padd=
ing-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=
=3D"ltr">
</div>
</blockquote></span></blockquote></blockquote>
I see that you want to add a new mechanism to define a new class
using another class as starting point, but I would not name this a
strong type proposal, even if it can be used to build some strong
types. Whether this is useful by itself needs more motivation and
concrete real examples.<span class=3D"gmail-im"></span><br></blockquote=
><div><blockquote><div><span class=3D"gmail-im"></span></div></blockquote><=
span class=3D"gmail-im">
</span>I don't understand. Even what you want from a strong typing =
proposal is still to define a new class from an old class. The only differe=
nce I see between what we are talking about is that I don't think editi=
ng the old class is useful enough compared to the downsides, and you don=
9;t.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px soli=
d rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><div dir=3D"l=
tr"><div>Why would you have copied A in the first place then, rather
than create a new class? </div></div></span></blockquote><span cl=
ass=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr">
</div>
</blockquote></span>
Add just N bazN() functions to A and you will see why it is
interesting to modify B because B doesn't want to provide the foo
function, but all the bazN functions.</blockquote><div><br></div><div>I=
do see that. The problem is that once a feature is out you don't get t=
o tell people how to use it. And people WILL misuse having the power to alt=
er everything every time. I don't believe it is possible to assume that=
this won't happen. Base on my personal experience, this will happen a =
lot, and it will be bad.<br></div><span class=3D"gmail-im"></span><br><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex">Note that inheritance allows y=
ou to make a member not accessible.<span class=3D"gmail-im"></span><br><spa=
n class=3D"gmail-im">
struct A {</span><br><span class=3D"gmail-im">
=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; }</span><br><sp=
an class=3D"gmail-im">
=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return foo(x) * 4.0; }<=
/span><br><span class=3D"gmail-im">
};</span><br><span class=3D"gmail-im">
</span><br><span class=3D"gmail-im"></span>
struct B : A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x);<br>
};</blockquote><div><br></div><div>I assume that you wanted to use publ=
ic inheritance. With private inheritance being an equivalent of encapsulati=
on, the assertion would not be interesting, since wrapping of course remove=
s access to the encapsulated data. With public inheritance, you did not mak=
e that member not accessible. It is still so, you have just hidden it.<br><=
br>B b;<br>b.A::bar(5);<br><br></div><div>There is a difference. In additio=
n, I don't believe that two wrongs make a right. Making a feature that =
can be potentially abused in the worst ways is not wise, I think.<br><br><b=
lockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-le=
ft:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><b=
lockquote type=3D"cite"><div dir=3D"ltr"><div><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex">One of the problems of
your proposal is that the copied class has access to the
private members, which is more subject to changes. I believe
that the copied class should only have access to public
members.</blockquote>
<div><br>
</div>
If one creates a new class, and private members cannot be
accessed, there will not be any way to touch them to do
anything else aside from the original interface. </div>
</div>
</blockquote></span>
Right.<span class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>This is also compounded by the fact that all old methods
accepting the original class won't work on the new class
(creating an operator Base() should be an exception for
certain use-cases, it should not be necessary to do so). </div>
</div>
</blockquote></span>
The Base conversion can be protected or private. The trampoline
would take care of this conversions.<span class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How are you going to print a copy? </div>
</div>
</blockquote></span>
Hmm, using the public interface or don't.<span class=3D"gmail-im"><=
br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How can you convert in a custom way to the original class?</di=
v>
</div>
</blockquote></span>
I don't see the use case. Maybe you have one.<span class=3D"gmail-i=
m"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div> How are you going to implement additional and useful
methods without access to privates?<br>
</div>
</div>
</blockquote></span>
If we need to access to private I believe it is worth creating a new
class. </blockquote><div><br></div><div>If I understand correctly, you =
want to be able to create a copy of another class, with the ability to alte=
r and access its public interface only. What happens when you delete a publ=
ic method used by a private method? What happens when you delete a public a=
ttribute used in private code? What happens to protected code - if not acce=
ssible you basically make inheritance useless on it? If in all these cases =
your answer is "the program will fail to compile, just copy the class =
by hand" then I think the feature would be severely limited in what it=
could actually do.<br></div><div><br></div><div>I feel that what you are p=
roposing is basically a fast way to create PIMPL wrappers. If I understand =
correctly, you want to hide the original completely, and just be offered an=
easy way to bring back some of its interface (via trampolines) to its &quo=
t;wrapper", which would be the strong typedef. Possibly adding more pu=
blic methods only using the public interface, which could be done just the =
same with non-member methods. The end result is a class that cannot be exte=
nded in any meaningful way using any of the normal C++ facilities, since ev=
ery juicy bit is hidden. Applying inheritance to it would require manual ex=
posure of all methods, with the limitations we have already discussed. Appl=
ying strong-typing again to a strong-typed class would be useless as access=
to internals would be the same, aside from possibly adding more data (if n=
eeded) in the public attributes, since only those are editable. This would =
also prevent encapsulation of new data. If not, it would just mean that the=
feature wouldn't be used in a composable way.<br><br></div><div>My own=
idea is to be able to extend an already existing class into a new class. I=
may not have 100% use cases for all things I'm proposing, but that is =
simply because I can't write in advance all possible programs with the =
feature. I just feel (maybe feeling is not enough, but opinions are also ma=
de of these unfortunately) that if a new feature has to be introduced it sh=
ould at least try to play ball with the rest of the language. The more it d=
oes, the more it can be used in any weird case that may come up. One of the=
most beautiful things about C++ is that there's pretty much always a w=
ay to do something, exactly because the language is flexible and its parts =
can be combined in many possible ways. A feature that creates a non-extenda=
ble object is like a dead-end.<br><br><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex">What I mean is that these wrappers should be part of the propo=
sal
and show how the your copy class reach to make concrete and real
opaque types as e.g the energy example in P0109.<span class=3D"gmail-im=
"></span><br><span class=3D"gmail-im"></span></blockquote><br></div><div>Bu=
t wrappers can be made in a separate library. Why should they be included i=
n the proposal? As long as the proposal allows them, a library only needs t=
o be made once (and if not needed by someone, not used).<br></div><div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left=
:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><blo=
ckquote type=3D"cite"><div dir=3D"ltr"><div>You see that in order to have a=
custom type, still many
things must be written. So what's the difference between
creating copyable wrappers (using normal C++ rules), and
creating a number of such interfaces (having to learn and
teach how protected/public/private work in a new context)? I
don't see what the difference would be. Why do you feel that
wrappers on primitive types are not enough?<br>
</div>
</div>
</blockquote></span>
Yes, the new opaque type must define all the available functions.
Note that p0109 provides conversions and the possibility to request
the compiler to generate the default trampolines. This is much
sorter than defining them using the current C++ language. Implicit
conversions (public) allow to use the new opaque type where the
underlying type was expected. <br>
<br>
I would prefer the opaque type proposal to go even further (or an
independent proposal) and be able to introduce groups of trampolines
as I did on my Opaque library with the combined mixins. However I
have no concrete proposal at the language level. <br></blockquote><div>=
<br></div><div>But I have made you an example with wrappers, which you also=
agreed is similar to what your library currently does. So what is wrong wi=
th that approach? <br></div><div><br><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex"><div>struct A {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
struct B : using A {};<br>
<br>
What will be the type of x<br>
<br>
B b1, b2;<br>
auto x =3D b1.append(b2);<br>
<br>
IIUC your proposal, the append function will be copied replacing any
occurrence of A by B, so it is as if B was declared<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
Am I missing something? (***)<br>
<br>
Or would B equivalent to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(B const&);<br>
};<br>
<br>
or to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
I'm wondering now if the copied class could add at all new
non-static data members. Otherwise I don't see how the duplication
of such function can be done. I suspect that p0109 doesn't allow to
add new data.<br>
Then, if the user wants to add more data, it should first duplicate
the class and then inherit from the duplicated class to add more
data.<span class=3D"gmail-im"><br></span></blockquote><br></div><div>No=
, you understood correctly, the end result would be <br><br></div><div><div=
>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br></div><div>Forcing the user to inherit to add more data adds inheri=
tance, which means that types are now implicitly convertible (to at least a=
common base). I don't think this is desirable. I think strong typing s=
hould work on its own.<br><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><d=
iv><div>In some sense creating a new foo overload using the
type-copy. However, I believe this would be a pretty big
change. </div>
</div>
</div>
</blockquote></span>
I believed this was already part of your proposal. (***)<span class=3D"=
gmail-im"><br></span></blockquote><div><br></div><div>Mhh, now that you put=
it this way. I thought about only doing this for classes. While the mechan=
ism for free functions would be the same (that's what I mean by strong-=
typedef of a function, see below), the scope would be wider. One only works=
for classes, the other on all free functions. I don't know, maybe divi=
ding them makes no sense. I'd love to hear what you think about this.<b=
r><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im=
"><blockquote type=3D"cite"><div dir=3D"ltr"><div><div>As this is outside o=
f the scope of my proposal, I did not
include this. And so, I cannot add to my proposal the
conversion of friend and non-member function when creating a
copy-type. If this could be included, there would be no
problem for that.<br>
</div>
</div>
</div>
</blockquote></span>
Sorry, I don't know yet what are type-aliases of methods. <br></blo=
ckquote><div><br></div><div>I'll try to explain myself better. A strong=
typedef of a function would be taking that function and replacing one or m=
ore types within it to others. You could say that when you do:<br><br></div=
><div>template <typename T><br></div><div>void foo(T);<br><br></div><=
div>then foo<int> and foo<double> are "strong typedefs&quo=
t; of each other, in some sense. If one were allowed to do this to existing=
code, one could do something like<br><br></div><div>void foo(int);<br><br>=
</div><div>void foo(double) : using foo(int);<br><br></div><div>to use an a=
nalogous syntax to the one in my proposal. Not sure if this is clearer, let=
me know.<br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px =
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><div><div>For=
example, consider<br>
<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
</div>
<div>};<br>
</div>
<div>struct C : using B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator B() =3D default;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
};<br>
<br>
</div>
<div>Just an idea.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I'm lost.<span class=3D"gmail-im"><br></span></blockquote><div><br>=
</div><div>What I mean is, if B is a strong typedef of A, then we can defau=
lt its conversion operator to A, right? But then, if C is a type-copy of B,=
then we can default its conversion operator to both B (since it's its =
type-copy), and also to A (since C is a type-copy of a type-copy).<br><br><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><=
blockquote type=3D"cite"><div dir=3D"ltr"><div><div><div><div>Is it really =
wise to allow the compiler to be able to
default convert B to A? </div>
</div>
</div>
</div>
</div>
</blockquote></span>
I would say, yes. The question p0109 raise is whether the user wants
it.<span class=3D"gmail-im"><br></span></blockquote><div><br></div><div=
>I'm not sure, however to me there's no difference either way.<br><=
br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord=
er-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-i=
m"><blockquote type=3D"cite"><div dir=3D"ltr"><div><div><div><div>Maybe. I =
thought that inherited classes are also
declared without mentioning that they inherit, so I
though that the same should hold for copies.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Maybe, but the C++ standard doesn't have constrains on whether the
class is derived from another class.<span class=3D"gmail-im"><br></span=
></blockquote><div><br></div><div>True. I'll try to think about this a =
bit more. Maybe we could simply lift the restriction and let the user do wh=
at he/she wants? (so also use classes that are not necessarily copies of th=
e originals, as long as their interface is compatible to what it needs to b=
e) <span class=3D"gmail-im"><br></span><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padd=
ing-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=
=3D"ltr"><div><div><div><div><div>That's true, and that's mostly wh=
at I don't like
about giving the ability to modify copied existing
methods. It is definitely non-obvious that this is
happening. If you make a mistake, it will take a long
time to figure out that you involuntarily modified the
behavior of the original class. That's bad in my book=
..<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Maybe you need something like override to state clearly that you
want to redefine the inherited behavior.<span class=3D"gmail-im"><br></=
span></blockquote><div><br></div><div>Unfortunately there would be nothing =
to override, as you are adding a new overload completely separate to the ol=
d one. Both would still be usable and work, nothing is being redefined. Sim=
ply the old function would get linked against the new implementation. There=
's nothing that the compiler could do to prevent this.<br><br></div><di=
v>Best,<br></div><div>Eugenio<br></div></div> </div></div></div></div></div=
></div></div></div></div><div class=3D"gmail_extra"><br><div class=3D"gmail=
_quote">On Sun, Jan 1, 2017 at 4:56 PM, Vicente J. Botet Escriba <span dir=
=3D"ltr"><<a href=3D"mailto:vicente.botet@wanadoo.fr" target=3D"_blank">=
vicente.botet@wanadoo.fr</a>></span> wrote:<br><blockquote class=3D"gmai=
l_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left=
:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"m_847778784893274403moz-cite-prefix">Le 31/12/2016 =C3=A0=
19:39, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
<br>
Eugenio, please, preserve some additional context in your
responses.<br>
<br>
From you responses, I believe that I have not understood your
proposal. See below (***)<br>
</div><span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex=
;border-left:1px solid rgb(204,204,204);padding-left:1ex">To
be honest, I will vote against this proposal if we can not
modify and delete existing functionality. When I copy/paste a
class I can change things and remove others.<span class=3D"m_8477=
78784893274403gmail-im"></span><br>
</blockquote>
<div><br>
</div>
<div>I really understand this feeling. However, consider this:
at which point is something a strong typedef of something
else, and when is it a new class? Is the mechanism we want to
introduce simply a way to declare a new class, using another
as a starting point and completely editable, or we want there
to be some kind of association (even if it was only on a
logical level) between the two things?<br>
</div>
</div>
</blockquote></span>
I see that you want to add a new mechanism to define a new class
using another class as starting point, but I would not name this a
strong type proposal, even if it can be used to build some strong
types. Whether this is useful by itself needs more motivation and
concrete real examples.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><br>
</div>
<div>A mechanism that freely allows you to edit classes wouldn'=
t
be a strong typedef, in my opinion. Consider:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void foo();<br>
};<br>
<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 void bar();<br>
};<br>
<br>
</div>
<div>Why would you have copied A in the first place then, rather
than create a new class? </div>
</div>
</blockquote></span>
Add just N bazN() functions to A and you will see why it is
interesting to modify B because B doesn't want to provide the foo
function, but all the bazN functions.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>If instead you could say "copies can only add" then =
when
you find a class declared as a copy you can easily reason
about it. Think about a long chains of copies:<br>
<br>
</div>
<div>struct A { /* .... */ };<br>
struct B : using A { /* .... */ };<br>
struct C : using B { /* .... */ };<br>
struct D : using C { /* .... */ };<br>
struct E : using D { /* .... */ };<br>
<br>
</div>
</div>
</blockquote>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>All these maybe in different files, in different places.
Then what is E? If you are allowed to remove and change
things, then you'd have to start at A and manually keep track
of which things are deleted, maybe re-added later, maybe
modified. It would be really hard to know exactly what E is.
While if you're allowed to only increment, it would be much
easier to know that - or at least on par with inheritance. If
you can find it once in the chain, then it exists. I believe
this is an important fact that must be considered when
thinking about what features we want in strong typing.<br>
</div>
</div>
</blockquote></span>
Note that inheritance allows you to make a member not accessible.<span =
class=3D""><br>
struct A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2; }<br>
=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return foo(x) * 4.0; }<=
br>
};<br>
<br></span>
struct B : A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x);<br>
};<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One of the prob=
lems of
your proposal is that the copied class has access to the
private members, which is more subject to changes. I believe
that the copied class should only have access to public
members.</blockquote>
<div><br>
</div>
If one creates a new class, and private members cannot be
accessed, there will not be any way to touch them to do
anything else aside from the original interface. </div>
</div>
</blockquote></span>
Right.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>This is also compounded by the fact that all old methods
accepting the original class won't work on the new class
(creating an operator Base() should be an exception for
certain use-cases, it should not be necessary to do so). </div>
</div>
</blockquote></span>
The Base conversion can be protected or private. The trampoline
would take care of this conversions.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How are you going to print a copy? </div>
</div>
</blockquote></span>
Hmm, using the public interface or don't.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How can you convert in a custom way to the original class?</di=
v>
</div>
</blockquote></span>
I don't see the use case. Maybe you have one.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div> How are you going to implement additional and useful
methods without access to privates?<br>
</div>
</div>
</blockquote></span>
If we need to access to private I believe it is worth creating a new
class. <br><span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><span class=3D"m_847778784893274403gmail-im"></span><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Again, I will v=
ote
against this proposal if it doesn't provides a solution for
builtin types, as this is IMHO one of the most appealing use
cases.<span class=3D"m_847778784893274403gmail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></blockquot=
e>
<br>
</div>
<div>A solution exists, and is the one that already exists when
one wants to limit operations done on existing types: build a
wrapper. The difference is that before a completely new
wrapper had to be built from scratch for each new needed
primitive alias, depending on the required operations, with
this proposal they become easily composable, so once done it
never has to be done again, and adding new types becomes a
one-liner for the user.<br>
</div>
</div>
</blockquote></span>
What I mean is that these wrappers should be part of the proposal
and show how the your copy class reach to make concrete and real
opaque types as e.g the energy example in P0109.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><br>
</div>
<div>Consider this against what p0109r0 does:<br>
<br>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">template
<class T =3D double></span></font></div>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">using
energy =3D protected double {</span></font></div>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">=C2=A0=C2=A0=C2=A0
energy operator+ (energy , energy) =3D default;</span></fon=
t></div>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">=C2=A0=C2=A0=C2=A0
energy& operator*=3D(energy&, T ) =3D default;</spa=
n></font></div>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">=C2=A0=C2=A0=C2=A0
energy operator*(energy , energy) =3D delete;</span></font>=
</div>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">=C2=A0=C2=A0=C2=A0
energy operator*(energy , T ) =3D default;</span></font></d=
iv>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">=C2=A0=C2=A0=C2=A0
energy operator*(T , energy) =3D default;</span></font></di=
v>
<div><font size=3D"2"><span style=3D"font-family:arial,helvetica,=
sans-serif">};</span></font></div>
<br>
</div>
<div>You see that in order to have a custom type, still many
things must be written. So what's the difference between
creating copyable wrappers (using normal C++ rules), and
creating a number of such interfaces (having to learn and
teach how protected/public/private work in a new context)? I
don't see what the difference would be. Why do you feel that
wrappers on primitive types are not enough?<br>
</div>
</div>
</blockquote></span>
Yes, the new opaque type must define all the available functions.
Note that p0109 provides conversions and the possibility to request
the compiler to generate the default trampolines. This is much
sorter than defining them using the current C++ language. Implicit
conversions (public) allow to use the new opaque type where the
underlying type was expected. <br>
<br>
I would prefer the opaque type proposal to go even further (or an
independent proposal) and be able to introduce groups of trampolines
as I did on my Opaque library with the combined mixins. However I
have no concrete proposal at the language level. <br><span class=3D"">
<font size=3D"2"><span style=3D"font-family:arial,helvetica,sans-serif"=
><br>
</span></font>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Your proposal h=
as already
this issue as you copy the whole class, and so you replace
every occurrence of the base class with the new class.<span cla=
ss=3D"m_847778784893274403gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I'm not sure what you mean. In my proposal, the copy is =
a
new class, and so it is always obvious what an assignment
operator is going to result in. In p0109r0 this is more
complex because depending on the access specifier different
default conversion operators are defined. Not sure what you
mean when you mention the replacement that happens, and what
the issue is.<br>
</div>
</div>
</div>
</blockquote>
<br>
<br>
</span><div>struct A {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
struct B : using A {};<br>
<br>
What will be the type of x<br>
<br>
B b1, b2;<br>
auto x =3D b1.append(b2);<br>
<br>
IIUC your proposal, the append function will be copied replacing any
occurrence of A by B, so it is as if B was declared<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
Am I missing something? (***)<br>
<br>
Or would B equivalent to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(B const&);<br>
};<br>
<br>
or to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
I'm wondering now if the copied class could add at all new
non-static data members. Otherwise I don't see how the duplication
of such function can be done. I suspect that p0109 doesn't allow to
add new data.<br>
Then, if the user wants to add more data, it should first duplicate
the class and then inherit from the duplicated class to add more
data.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I don't k=
now what do
you mean by type-aliases of methods. Could you elaborate?<spa=
n class=3D"m_847778784893274403gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Yes. So consider this:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0 =C2=A0 friend void foo(A&);<br>
};<br>
<br>
</div>
struct B : using A {};<br>
<br>
</div>
<div>To me the only way to allow B to also have the friend
declaration is if we could do the following transformation:<br>
<br>
</div>
<div>void foo(A&) ----> void foo(B&)<br>
</div>
</div>
</div>
</blockquote></span>
Right.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
</div>
<div>In some sense creating a new foo overload using the
type-copy. However, I believe this would be a pretty big
change. </div>
</div>
</div>
</blockquote></span>
I believed this was already part of your proposal. (***)<span class=3D"=
"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>If such a thing was allowed, then why stop at copies? Why
not being able to define<br>
<br>
</div>
<div>void foo(A&) ----> void foo(C&)<br>
<br>
</div>
<div>or even<br>
<br>
</div>
<div>void foo(A&) ----> template<typename T> void
foo(T&);<br>
<br>
</div>
<div>As this is outside of the scope of my proposal, I did not
include this. And so, I cannot add to my proposal the
conversion of friend and non-member function when creating a
copy-type. If this could be included, there would be no
problem for that.<br>
</div>
</div>
</div>
</blockquote></span>
Sorry, I don't know yet what are type-aliases of methods.
<span class=3D""><blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Could you ela=
borate?
(on recursive conversion operator)<span class=3D"m_8477787848=
93274403gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>For example, consider<br>
<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
</div>
<div>};<br>
</div>
<div>struct C : using B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator B() =3D default;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D default;<br>
};<br>
<br>
</div>
<div>Just an idea.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I'm lost.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_847778784893274403gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a
conversion operator would be disabled if
the copy has added new attributes with
respect to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Why?<span class=3D"m_847778784893274403gmail-im"><b=
r>
</span></blockquote>
<div><br>
</div>
<div>I think that at that point the two classes diverged
enough that the compiler cannot assume they can be
converted freely? If I have:<br>
<br>
</div>
<div>struct A { int x; };<br>
</div>
<div>struct B : using A { int y; };<br>
<br>
</div>
<div>Is it really wise to allow the compiler to be able to
default convert B to A? </div>
</div>
</div>
</div>
</div>
</blockquote></span>
I would say, yes. The question p0109 raise is whether the user wants
it.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>If they were the same, ok, but maybe at that point
the user should be forced to provide a conversion
operator, no?<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
If the user decides to provide the default implementation I don't
see where the problem is.<br>
<br>
operator Base() =3D default;<br>
<br>
The compiler know how to do the conversion.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I don'=
;t know
compiler writers would like to look ahead. I believe
that C should be forward declared as a copy.<span class=
=3D"m_847778784893274403gmail-im"><br>
</span></blockquote>
<br>
</div>
<div>Maybe. I thought that inherited classes are also
declared without mentioning that they inherit, so I
though that the same should hold for copies.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Maybe, but the C++ standard doesn't have constrains on whether the
class is derived from another class.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I will ne=
ed a
concrete example of when a complete hierarchy must be
"duplicated". I'm not saying there are no c=
ases, just
I have no one in my head.<span class=3D"m_847778784893274=
403gmail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></blo=
ckquote>
<br>
</div>
<div>I'll try to add these on the concrete examples.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">You are n=
ot
modifying here, but adding ;-). You can say it is
ambiguous, but we have this case with inheritance (<a cla=
ss=3D"m_847778784893274403gmail-m_2667955782052143795moz-txt-link-freetext"=
href=3D"http://melpon.org/wandbox/permlink/f9mRtE9n5mA9RPpl" target=3D"_bl=
ank">http://melpon.org/wandbox/per<wbr>mlink/f9mRtE9n5mA9RPpl</a>)<span cla=
ss=3D"m_847778784893274403gmail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></blo=
ckquote>
<br>
</div>
<div>Not quite, the resulting copied class would be
equivalent to<br>
<br>
</div>
<div>
<div>struct C {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2=
; }<br>
<span class=3D"m_847778784893274403gmail-im">=C2=A0=C2=A0=
=C2=A0=C2=A0 double foo(int x) { return
x * 2; }</span><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return=
foo(x) * 4.0; }<br>
};<br>
<br>
</div>
<div>which is illegal, since you cannot overload on
return type. Keep in mind that there is no "layer&qu=
ot;
between the original class and what gets added to the
copy.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You are right. I missed that all the function are copied. In this
case, either a function is not copied when there is an added
function with the same overloaded signature or the program is ill
formed.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I don&#=
39;t see a
problem here as D is a copy of A and then we are
defining its meaning.<br>
You said that it should be as simple as if defined
the class by hand.<span class=3D"m_847778784893274403gm=
ail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></b=
lockquote>
<br>
</div>
<div>That's true, and that's mostly what I don'=
t like
about giving the ability to modify copied existing
methods. It is definitely non-obvious that this is
happening. If you make a mistake, it will take a long
time to figure out that you involuntarily modified the
behavior of the original class. That's bad in my book=
..<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Maybe you need something like override to state clearly that you
want to redefine the inherited behavior.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I belie=
ve it is
worth mentioning it in the proposal. My
TBoost.Opaque library implements something like
that. I will start a new thread to talk about the
TBoost.Opaque library approach. If I need a library
solution for builtin types, why this library
solution will not work for classes, what will be the
added value of the language solution?<span class=3D"m_8=
47778784893274403gmail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></b=
lockquote>
<br>
</div>
<div>I believe that wrapper types are just as good as
primitive types. This is also how it's always been in
C++. The main problem was simply that doing this over
and over and over was incredibly unwieldy. I don't
believe that the reason why the older, in-C++
approaches didn't work is that they were creating
wrappers rather than "primitive type aliases". =
This
proposal eliminates the need for repetition as once
done, it is done forever. A library like boost can
pre-produce often used primitive types wrappers once
in a single header, and be done forever.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">No p010=
9r0
doesn't define any operation by default (except
conversions). The user needs to add whatever is
needed, maybe using the default trampoline
implementation). Well this is how I understand it.<span=
class=3D"m_847778784893274403gmail-im"></span><br>
<span class=3D"m_847778784893274403gmail-im"></span></b=
lockquote>
<br>
</div>
<div>From the proposal: "<span style=3D"font-family:ar=
ial,helvetica,sans-serif"><font size=3D"2">Since all member functions of th=
e
underlying type are known to the compiler, we can
take advantage of this and therefore propose that
the compiler, </font></span><span style=3D"font-famil=
y:arial,helvetica,sans-serif"><font size=3D"2">by default, generate default=
versions of
these trampolines."<br>
</font></span></div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span><font size=3D"2">I interpret this as the compiler could generate=
them
by default, once the user has requested it using the =3D default
syntax. I agree the proposal doesn't contain examples where this
is clear enough.</font><br>
<br>
<br>
<br>
Vicente<br>
<blockquote type=3D"cite"><div><div class=3D"h5">
<div dir=3D"ltr">
<div><span class=3D"m_847778784893274403gmail-im"></span></div>
</div>
<div class=3D"gmail_extra"><br>
<div class=3D"gmail_quote">On Sat, Dec 31, 2016 at 6:15 PM,
Vicente J. Botet Escriba <span dir=3D"ltr"><<a href=3D"mailto:=
vicente.botet@wanadoo.fr" target=3D"_blank">vicente.botet@wanadoo.fr</a>>=
;</span>
wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bord=
er-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span>
<div class=3D"m_847778784893274403m_2667955782052143795moz-=
cite-prefix">Le
31/12/2016 =C3=A0 15:57, Eugenio Bargiacchi a =C3=A9crit=
=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Dear Vincente,<br>
<br>
</div>
Thank you for your very in-depth review. I've
updated the proposal using already received
comments from this thread, so some things have
changed, but it's still alright to receive
comments on this version. I'll explain below
how it has changed when answering to your
comments.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
>IIUC,
every occurrence of the base type in the
definition of the base type is replaced by
the new type. This is one of the options
described in Opaque proposal (see The return
type issue). Why the other alternatives have
less sens?<span class=3D"m_847778784893274403m_=
2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_847778784893274403m_2667955782=
052143795m_-5826156030849956333gmail-im"></span></blockquote>
<span class=3D"m_847778784893274403m_266795578205=
2143795m_-5826156030849956333gmail-im">
</span><br>
</div>
There are many differences between my proposal
and the Opaque proposal. I believe that the main
ones that this proposal brings are:<br>
<br>
</div>
- Where possible, do not introduce new meanings or
rules to the language. The type-copied class
should behave as closely as possible to a class
the user has implemented by hand. This should make
very easy to understand how the feature works,
without the need to grasp many new concepts.<br>
</div>
- I have removed the option to modify and remove
existing functionality from the class that is being
copied. While I believe that this can be useful, it
introduces too much complexity in my opinion now. If
this is allowed, you basically have to create a
system where you are allowed to completely rewrite
an existing class starting from another, since you
may want to copy or remove or change anything that
was previously present. This I believe can both make
the proposal unnecessary complicated, and can make
the code very hard to follow, as at each new
strong-typedef step (since a type could be copied,
and the copy copied again and so on) anything could
happen. I now believe that an incremental-only
strategy (similar to inheritance) can still be both
useful and sufficient for most cases. Where it is
not, simple implementations by hand of basic
functionality, extended then via the type-copy
mechanism should result in clear, reusable code
which still requires little maintenance.<br>
</div>
</blockquote>
</span> To be honest, I will vote against this proposal if
we can not modify and delete existing functionality. When
I copy/paste a class I can change things and remove
others.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr"><br>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
>The word
duplicating and wrapping don't match. The
proposed approach doesn't wraps the
underlying type, except maybe for builtin
types.<br>
</blockquote>
<br>
</div>
<div>Right, I'll fix it, thanks.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
>I believe
the proposal needs to add some concrete
examples as use cases<br>
</blockquote>
</div>
<div><br>
</div>
<div>This makes sense, I'll worn ok an
additional section where I try to show some
concrete examples.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> The best will be to add them in the motivation
section showing how the new feature is used instead of
some flat code.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
>If the
base class change, the strong types
depending on it could need maintenance also,
isn't it?<span class=3D"m_84777878489327440=
3m_2667955782052143795m_-5826156030849956333gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True, however wrapper methods have to be
fixed 100% of the time, while a type-copied
class may not need this. It's the same as i=
f
one modified a base class in inheritance -
you don't have to necessarily update all th=
e
code that depends on it right away.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> One of the problems of your proposal is that the
copied class has access to the private members, which is
more subject to changes. I believe that the copied class
should only have access to public members.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">In
addition to these basic techniques, there
are other library solution, as e.g. using
CRTP that might merit to be mentioned.<br>
See [TBoost.Opaque] for a possible
implementation.<span class=3D"m_8477787848932=
74403m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_847778784893274403m_26679557=
82052143795m_-5826156030849956333gmail-im"></span></blockquote>
<br>
</div>
<div>I'll add a mention to CRTP. I'll giv=
e a
look at the boost link, thanks!<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">Please
add <a class=3D"m_847778784893274403m_2667955=
782052143795m_-5826156030849956333gmail-m_-7522649930861642754moz-txt-link-=
freetext" href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p=
0109r0.pdf" target=3D"_blank">http://www.open-std.org/jtc1/s<wbr>c22/wg21/d=
ocs/papers/2015/p010<wbr>9r0.pdf</a>
to this list.<span class=3D"m_847778784893274=
403m_2667955782052143795m_-5826156030849956333gmail-im"></span><br>
<span class=3D"m_847778784893274403m_26679557=
82052143795m_-5826156030849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Thanks, I must have missed it.<br>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">What is
wrong for you with p0109r0 approach?<br>
What we could have with your approach that
we cannot have with p0109r0?<br>
What we could have with p0109r0 that we
cannot have with your approach?<br>
<br>
IIUC, p0109r0 opaque types don't introduc=
e
any operations by default other than
conversions and your proposal introduce
all members but no friends<span class=3D"m_84=
7778784893274403m_2667955782052143795m_-5826156030849956333gmail-im"></span=
><br>
<span class=3D"m_847778784893274403m_26679557=
82052143795m_-5826156030849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Personally, I don't think there's
anything "wrong" with p0109r0. The id=
ea for
this proposal came to me before I knew the
alternatives, but since C++ still does not
have strong typedefs I thought I might as
well propose an alternative approach, which
could possibly garner more interest.<br>
<br>
</div>
<div>I believe my approach is simpler to read
and more intuitive - especially when
creating strong aliases of very complex
types, but that can definitely be bias. It
can be applied to hierarchies of classes,
since it allows type-copying interdependent
classes, which I believe is very important.
It is very easy to use with templates and
specializations, which potentially gives it
a lot of power and very many potential uses.
It is easily composable, as in copying a
copy is very easy and indeed expected in my
view for the feature.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You will need to show how all this arguments
applies on concrete examples and how p0109r0 could do the
same thing.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>With p0109r0 there's more flexibility to
alter a type. The additional flexibility
allows it to take on more tasks, as in
type-copying friends, since default ways to
convert to the original types exist. It is
designed for primitive types first, while I
have actually removed them in my last
iteration for a number of reasons (see
below). </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Again, I will vote against this proposal if it
doesn't provides a solution for builtin types, as this is
IMHO one of the most appealing use cases.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The additional flexibility however comes
at a cost, as you mention the return type
issue, which my proposal does not have.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Your proposal has already this issue as you copy
the whole class, and so you replace every occurrence of
the base class with the new class.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<div>I don't introduce friends mostly because
a feature to create type-aliases of methods
does not currently exist, </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't know what do you mean by type-aliases of
methods. Could you elaborate?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>and I don't believe it is wise to add it
to the scope of this proposal since it would
be another very large change. If such a
feature existed, however, adding friends to
a type-copied class in my proposal would be
trivial, as simply strong typedefs of the
needed functions could be created on the
fly. The same could also be done for
non-member functions if needed, but how that
would work I have not thought about yet.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Could you elaborate how type-aliases of methods
would help here?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">I find
that conversions to/from the underlying
type must be covered by the proposal. If
we change the Base type we don't want to
be forced to redefine the conversion
operator.<br>
Maybe we need some kind of default
conversion implementation<br>
<span style=3D"font-family:courier new,monosp=
ace">=C2=A0=C2=A0=C2=A0 operator Base() <b>=3D
default</b>;</span><br>
<span style=3D"font-family:courier new,monosp=
ace"> or </span><br>
<span style=3D"font-family:courier new,monosp=
ace">=C2=A0=C2=A0=C2=A0 <b>explicit</b>
operator Base() <b>=3D default</b>;</span><=
br>
</blockquote>
</div>
<div><br>
</div>
<div>I like this. I didn't add it to keep the
number of features as low as reasonably
possible, but this is simple enough. This
could also be used recursively, as in a copy
of a copy could define a conversion operator
to both the first copy and the original in
this way. </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Could you elaborate?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>However, this default way to define a
conversion operator would be disabled if the
copy has added new attributes with respect
to its original class.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Why?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">Why do
you introduce this restriction? (on
template parameter numbers)<br>
</blockquote>
</div>
<div><br>
</div>
<div>No actually, you're right. I should lift
it. I thought initially that there wouldn't
be any reason to add more template
parameters, as they would only be needed to
satisfy the original class. But this is
definitely wrong. I'll change it, thanks.<b=
r>
</div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">In **
above C has not yet defined as a copy<span cl=
ass=3D"m_847778784893274403m_2667955782052143795m_-5826156030849956333gmail=
-im"></span><br>
<span class=3D"m_847778784893274403m_26679557=
82052143795m_-5826156030849956333gmail-im"></span></blockquote>
<br>
</div>
<div>Ill explain how I believe this example
should work. Since C has been declared but
not defined when parsing D, the compiler
will be allowed to assume that C is going to
be defined later as a type-copy of A. If
that does not happen, then the compiler will
give an error, either at the definition of C
or of D, explaining that D assumed that C
would have been a type-copy while it was
not. If C has added new attributes to its
declaration though D's definition would nee=
d
to take the new size of C into account
though. Not sure if this can be done or if
it should result in an error.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't know compiler writers would like to look
ahead. I believe that C should be forward declared as a
copy.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">I
believe this interdependent case introduce
a lot of complexity. We would need a good
use case to introduce it on the standard.<spa=
n class=3D"m_847778784893274403m_2667955782052143795m_-5826156030849956333g=
mail-im"></span><br>
<span class=3D"m_847778784893274403m_26679557=
82052143795m_-5826156030849956333gmail-im"></span></blockquote>
<br>
</div>
<div>A very simple example would be copying of
inherited classes, both base and derived.
Without a way to do this that just cannot be
done. This can be important if one does not
want that the derived type and its type-copy
are allowed to be converted to the same
base. This is a strong reason, I believe,
otherwise strong-typing in that case just
lost some power in keeping original and
type-copy apart.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I will need a concrete example of when a complete
hierarchy must be "duplicated". I'm not saying =
there are
no cases, just I have no one in my head.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">I
believe that this cannot be optional as in
a lot of cases we need to modify/restrict
the base type interface.<br>
</blockquote>
<br>
</div>
<div>I have actually removed this in my newest
revision. I believe that ground-up building
of types is the better way to go (as is
normally done in inheritance). Having the
power to completely alter the original type,
possibly to a point where there was not even
much in common between the original and the
type-copy, is not worth it. This is a
personal opinion, but I believe doing so can
prevent some very complex and ugly code
smells, at a not incredible cost.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> We need to solve concrete problems. The 1st use
case I have for strongly types is to reduce the interface
provided by the underlying type and to adapt the functions
signatures to the new class.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
>
<div>Could you give a concrete example of
this kind of problems?<br>
</div>
</blockquote>
<div>
<div style=3D"margin-left:40px"><span class=3D"=
m_847778784893274403m_2667955782052143795m_-5826156030849956333gmail-im"></=
span></div>
<br>
</div>
<div>Suppose<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { re=
turn x * 2; }<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x=
) { return foo(x)
* 4.0; }<br>
};<br>
</div>
<div><br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int foo(int) =3D delete;<=
br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // bar cannot compile any=
more<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Where is the problem? struct B will not compile.
That's all.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct C : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(int x) { retur=
n x * 2; }<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // ambiguous definition<b=
r>
};<br>
</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are not modifying here, but adding ;-). You
can say it is ambiguous, but we have this case with
inheritance (<a class=3D"m_847778784893274403m_26679557820521=
43795moz-txt-link-freetext" href=3D"http://melpon.org/wandbox/permlink/f9mR=
tE9n5mA9RPpl" target=3D"_blank">http://melpon.org/wandbox/per<wbr>mlink/f9m=
RtE9n5mA9RPpl</a>)<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>struct D : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 double foo(double x) { re=
turn x * 3;
}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // Changes meaning of bar
underhandedly with no warning<br>
</div>
<div>};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I don't see a problem here as D is a copy of A an=
d
then we are defining its meaning.<br>
You said that it should be as simple as if defined the
class by hand.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>I suppose even more dangerous and complex
cases could be devised.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> We will need some real examples to see how
dangerous they are ;-)<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">While
this is inline with your approach, this
merits some explanations as the operators
are no members. Shouldn't the operators o=
f
UDT classes meritt to be inherited as
well?<br>
</blockquote>
<div><br>
</div>
<div>I've removed primitive type support
also for this reason. They are not
currently treated as classes by C++, and
so I think I shouldn't either. Instead my
approach is now constructive. If one
needed aliases for primitive types, one
could create a single header of wrappers
in the form<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>class SimpleWrapper {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 public:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
SimpleWrapper(T t) : t_(t) {}<br>
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
T t_;<br>
</div>
<div>};<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>struct SimpleWrapperWithSum : using
SimpleWrapper<T> {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 SimpleWrapperWithSum
operator+(const SimpleWrapperWithSum &
other) { return t_ + other.t_; }<br>
</div>
<div>};<br>
<br>
</div>
<div>And so on. It would only be needed
once, and then users could simply copy the
versions with the operators they need to
use. It's not incredibly pretty and it
does have some limitations, but it works,
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe it is worth mentioning it in the
proposal. My TBoost.Opaque library implements something
like that. I will start a new thread to talk about the
TBoost.Opaque library approach. If I need a library
solution for builtin types, why this library solution will
not work for classes, what will be the added value of the
language solution?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>and in any case even in p0109r0 one
would need to remove all unneeded
operators, so work would need to be done
anyway. <br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> No p0109r0 doesn't define any operation by defaul=
t
(except conversions). The user needs to add whatever is
needed, maybe using the default trampoline
implementation). Well this is how I understand it.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div><br>
</div>
<blockquote class=3D"gmail_quote" style=3D"marg=
in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e=
x">
<div>I believed that there where no
implicit conversions on your proposals.
How (*this) is converted to an int?<br>
<br>
What would be the result type of x
below?<br>
<br>
Id id(1);<br>
auto x =3D +id;<br>
<br>
I suspect that it would be Id.<span class=
=3D"m_847778784893274403m_2667955782052143795m_-5826156030849956333gmail-im=
"></span><br>
</div>
</blockquote>
<div>
<blockquote><span class=3D"m_8477787848932744=
03m_2667955782052143795m_-5826156030849956333gmail-im"></span></blockquote>
Yeah, this was a weird syntax, I thought
it could be a simple way to represent
conversion to the underlying primitive
type.<br>
<br>
The type of the operation would be Id,
yes. I believe that to be the only
intuitive result that makes sense, unless
an explicit operator+ that does a
conversion has been defined somewhere. If
a cast is needed, one needs to cast. I
don't see a reason to change that for
strong typedefs, otherwise the language
would be inconsistent IMO.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex">Why
this restriction is needed or desirable.<sp=
an class=3D"m_847778784893274403m_2667955782052143795m_-5826156030849956333=
gmail-im"> (w.r.t.
final in type-copies of primitive
types)<br>
</span></blockquote>
<div><br>
</div>
<div>It is not. But I believe that if one
needs to do something, it has to be in
line with the rest of the language. If a
strong typedef of a primitive type is
needed, it would still need to follow
the rules of primitive types. </div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> It depends. If a strong type is able to define new
members it is not anymore a builtin and becomes for me a
class.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>As primitive types are not
inheritable, I believe neither should
the strong typedefs. Maybe this is a
wrong position, I don't know (since
primitive typedefs are not inheritable
due to C compatibilities IIUC), but I
believe that having consistency is still
useful for a proposal. Otherwise one
needs to always learn a million
exceptions to each rule, and that I
don't like, where it can be avoided. In
any case, these are my opinions, but if
there is strong consensus to change how
the proposal works I have no problem in
modifying it.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You need to justify your decisions on a rationale
section. But as you have removed builtin types as base
types this is not needed anymore. You will need to justify
why builtin are not supported :(=C2=A0 <br>
<span>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-lef=
t:1ex">Example
of where this can be useful welcome.<br>
</blockquote>
<div><br>
</div>
<div>I must admit I didn't really think
about this, I just thought they could
be nice to have. Maybe they would be
useless. I just considered that
sometimes the ingenuity of how people
use tools always seem to surprise, so
why not. Maybe in order to SFINAE the
generation of conversion operators to
classes, given that they are copies of
the original? Something like<br>
<br>
</div>
<div>struct Copy : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 template <=
typename T, /*
enable_if_t<is_copy_of_v<T,
A>>> */><br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0 operator T =
=3D default;<br>
</div>
<div>};<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Features must be added to solve concrete problems.<br=
>
<br>
I suggest you to work on the motivation section with real
concrete examples.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex">How
other type traits behave for the
copied class (see p0109r0)?<br>
</blockquote>
<br>
</div>
<div>All other type traits behave as if
the class had been implemented by
hand, and is separate from the
original. so is_same would return
false, for example. It seems that
p0109r0 thinks the same way. The only
difference is that sizeof may be
different, since in my proposal one
could add additional attributes to the
type-copied class. (There's no
examples in the old version, I've
added them on GitHub though).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I agree for is_same of course. I was wondering for
other traits that could have been specialized for the base
class. I suspect the answer is that the user would need to
specialize the new type again.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Thanks again for your feedback.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are welcome,<br>
Vicente<br>
<br>
</div>
<span>
-- <br>
You received this message because you are subscribed to a
topic in the Google Groups "ISO C++ Standard - Future
Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://grou=
ps.google.com/a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" t=
arget=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-pr=
oposals<wbr>/gkJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an
email to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.o=
rg" target=3D"_blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-pr=
oposals@isocpp.org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
</span>
To view this discussion on the web visit <a href=3D"https://gro=
ups.google.com/a/isocpp.org/d/msgid/std-proposals/f4a57116-c65b-94f4-51f2-e=
5cf8b4ff3ca%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=
=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/std-proposa=
ls<wbr>/f4a57116-c65b-94f4-51f2-<wbr>e5cf8b4ff3ca%40wanadoo.fr</a>.<br>
</blockquote>
</div>
<br>
</div>
-- <br></div></div><span class=3D"">
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Future Proposals" group.<br></sp=
an>
To unsubscribe from this group and stop receiving emails from it,
send an email to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.o=
rg" target=3D"_blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<span c=
lass=3D""><br>
To post to this group, send email to <a href=3D"mailto:std-proposals@=
isocpp.org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.go=
ogle.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtVBKZOMtpURNBDCEJijF=
L_J5s%2BROrLwJfkRgGyWzZMgg%40mail.gmail.com?utm_medium=3Demail&utm_sour=
ce=3Dfooter" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/=
d/msgid/std-<wbr>proposals/CAHfn%3D%<wbr>2BtVBKZOMtpURNBDCEJijFL_J5s%<wbr>2=
BROrLwJfkRgGyWzZMgg%40mail.<wbr>gmail.com</a>.<br>
</blockquote>
<p><br>
</p>
</div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ef8190c7-f46f-cf76-7e45-2114a84eae27%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/ef81=
90c7-f46f-cf76-<wbr>7e45-2114a84eae27%40wanadoo.fr</a><wbr>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtEbHpzdtK40qS_tVUPfPyKnOft=
-ZXOTMTDezPDzS3fAw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
>https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtE=
bHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw%40mail.gmail.com</a>.<br />
--94eb2c03c7908d1bfd05450bbbd4--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Mon, 2 Jan 2017 00:30:17 +0100
Raw View
This is a multi-part message in MIME format.
--------------89CEE71906F4E0C909D27C43
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 01/01/2017 =C3=A0 18:26, Eugenio Bargiacchi a =C3=A9crit :
Eugenio, I believe the use cases we have both in mind are quite=20
different, and so we don't reach to understand one to each other.
I have a question. Does you copy class proposal needs to have the=20
definition of the copied class available?
If yes, I don't think this could be acceptable.
If the declaration is enough, the copied functions would need at least=20
an internal conversion to/from the underlying type, isn't it?
>
> Note that inheritance allows you to make a member not accessible.
> struct A {
> int foo(int x) { return x * 2; }
> double bar(double x) { return foo(x) * 4.0; }
> };
>
> struct B : A {
> private:
> double bar(double x);
> };
>
>
> I assume that you wanted to use public inheritance. With private=20
> inheritance being an equivalent of encapsulation, the assertion would=20
> not be interesting, since wrapping of course removes access to the=20
> encapsulated data. With public inheritance, you did not make that=20
> member not accessible. It is still so, you have just hidden it.
>
> B b;
> b.A::bar(5);
>
Agreed. And the language let me do that even if you find it could be bad=20
practice. I don't see why your copy approach wouldn't let me do that.
> There is a difference. In addition, I don't believe that two wrongs=20
> make a right. Making a feature that can be potentially abused in the=20
> worst ways is not wise, I think.
>
>> One of the problems of your proposal is that the copied class
>> has access to the private members, which is more subject to
>> changes. I believe that the copied class should only have
>> access to public members.
>>
>>
>> If one creates a new class, and private members cannot be
>> accessed, there will not be any way to touch them to do anything
>> else aside from the original interface.
> Right.
>> This is also compounded by the fact that all old methods
>> accepting the original class won't work on the new class
>> (creating an operator Base() should be an exception for certain
>> use-cases, it should not be necessary to do so).
> The Base conversion can be protected or private. The trampoline
> would take care of this conversions.
>> How are you going to print a copy?
> Hmm, using the public interface or don't.
>> How can you convert in a custom way to the original class?
> I don't see the use case. Maybe you have one.
>> How are you going to implement additional and useful methods
>> without access to privates?
> If we need to access to private I believe it is worth creating a
> new class.=20
>
>
> If I understand correctly, you want to be able to create a copy of=20
> another class, with the ability to alter and access its public=20
> interface only. What happens when you delete a public method used by a=20
> private method?
Compile error ?
> What happens when you delete a public attribute used in private code?
We can not remove data members, otherwise we can not share the same=20
representation.
> What happens to protected code - if not accessible you basically make=20
> inheritance useless on it?
Good question. With the wrapping approach, you couldn't inherit from it.=20
With you approach, the data will be copied. The question is if the=20
strong-type has access to this protected data.
I have never needed to create a duplicate of a class that is part of=20
inheritance hierarchy. I've always wrapped final classes. Some examples=20
will help me to clarify the need.
I believe we could have duplication having access only to the public=20
part and let the derived classes use the protected part. Nevertheless I=20
could live providing access to the protected part.
> If in all these cases your answer is "the program will fail to=20
> compile, just copy the class by hand" then I think the feature would=20
> be severely limited in what it could actually do.
You are probably right, and the copy should copy every thing and give=20
access to everything internally. I need some concrete examples to=20
understand what this possibility will solve.
>
> I feel that what you are proposing is basically a fast way to create=20
> PIMPL wrappers.
Not at all.
> If I understand correctly, you want to hide the original completely,=20
> and just be offered an easy way to bring back some of its interface=20
> (via trampolines) to its "wrapper", which would be the strong typedef.
I wouldn't say hiding, just don't looking inside the underlying type. I=20
want to provide access to it (when needed) but only as a whole.
> Possibly adding more public methods only using the public interface,=20
> which could be done just the same with non-member methods. The end=20
> result is a class that cannot be extended in any meaningful way using=20
> any of the normal C++ facilities, since every juicy bit is hidden.
Why it is unusable? The class provide access to everything you want.
> Applying inheritance to it would require manual exposure of all=20
> methods, with the limitations we have already discussed.
I don't follow you here.
> Applying strong-typing again to a strong-typed class would be useless=20
> as access to internals would be the same,
You can strong-type again. I don't see the trouble. E.g; you can have a=20
energy strong-type and have kinetic_energy, potential_energy and =20
heat_energy strong-type of energy.
Typing and representation are two different things. Strong types are=20
just that. Share a representation and have different types.
> aside from possibly adding more data (if needed) in the public=20
> attributes, since only those are editable. This would also prevent=20
> encapsulation of new data. If not, it would just mean that the feature=20
> wouldn't be used in a composable way.
I believe now that strong-type shouldn't add any new non-static data member=
..
>
> My own idea is to be able to extend an already existing class into a=20
> new class. I may not have 100% use cases for all things I'm proposing,=20
> but that is simply because I can't write in advance all possible=20
> programs with the feature. I just feel (maybe feeling is not enough,=20
> but opinions are also made of these unfortunately) that if a new=20
> feature has to be introduced it should at least try to play ball with=20
> the rest of the language. The more it does, the more it can be used in=20
> any weird case that may come up. One of the most beautiful things=20
> about C++ is that there's pretty much always a way to do something,=20
> exactly because the language is flexible and its parts can be combined=20
> in many possible ways. A feature that creates a non-extendable object=20
> is like a dead-end.
I must agree with your last sentence, but I don't think the strong-types=20
I'm suggesting are non-extendable?
>
> What I mean is that these wrappers should be part of the proposal
> and show how the your copy class reach to make concrete and real
> opaque types as e.g the energy example in P0109.
>
>
> But wrappers can be made in a separate library. Why should they be=20
> included in the proposal? As long as the proposal allows them, a=20
> library only needs to be made once (and if not needed by someone, not=20
> used).
We need some probe of concept applied to concrete examples we want to=20
solve. I believe a strong type feature must solve the builtin type case.=20
If your proposal is not a strong type proposal, then forget my comments.
>
>> You see that in order to have a custom type, still many things
>> must be written. So what's the difference between creating
>> copyable wrappers (using normal C++ rules), and creating a number
>> of such interfaces (having to learn and teach how
>> protected/public/private work in a new context)? I don't see what
>> the difference would be. Why do you feel that wrappers on
>> primitive types are not enough?
> Yes, the new opaque type must define all the available functions.
> Note that p0109 provides conversions and the possibility to
> request the compiler to generate the default trampolines. This is
> much sorter than defining them using the current C++ language.
> Implicit conversions (public) allow to use the new opaque type
> where the underlying type was expected.
>
> I would prefer the opaque type proposal to go even further (or an
> independent proposal) and be able to introduce groups of
> trampolines as I did on my Opaque library with the combined
> mixins. However I have no concrete proposal at the language level.
>
>
> But I have made you an example with wrappers, which you also agreed is=20
> similar to what your library currently does. So what is wrong with=20
> that approach?
I believe we are not understanding one each other. My two last=20
paragraphs don't concern your proposal. It concerns p0109.
>
> struct A {
> A append(A const&);
> };
>
> struct B : using A {};
>
> What will be the type of x
>
> B b1, b2;
> auto x =3D b1.append(b2);
>
> IIUC your proposal, the append function will be copied replacing
> any occurrence of A by B, so it is as if B was declared
>
> struct B {
> B append(B const&);
> };
>
> Am I missing something? (***)
>
> Or would B equivalent to
>
> struct B {
> A append(B const&);
> };
>
> or to
>
> struct B {
> A append(A const&);
> };
>
> I'm wondering now if the copied class could add at all new
> non-static data members. Otherwise I don't see how the duplication
> of such function can be done. I suspect that p0109 doesn't allow
> to add new data.
> Then, if the user wants to add more data, it should first
> duplicate the class and then inherit from the duplicated class to
> add more data.
>
>
> No, you understood correctly, the end result would be
>
> struct B {
> B append(B const&);
> };
>
Great.
> Forcing the user to inherit to add more data adds inheritance, which=20
> means that types are now implicitly convertible (to at least a common=20
> base). I don't think this is desirable. I think strong typing should=20
> work on its own.
How then you will be able to construct a B from a A if B adds more=20
non-static data members?
>
>> In some sense creating a new foo overload using the type-copy.
>> However, I believe this would be a pretty big change.
> I believed this was already part of your proposal. (***)
>
>
> Mhh, now that you put it this way. I thought about only doing this for=20
> classes.
Do you mean for member functions?
> While the mechanism for free functions would be the same (that's what=20
> I mean by strong-typedef of a function, see below), the scope would be=20
> wider. One only works for classes, the other on all free functions. I=20
> don't know, maybe dividing them makes no sense. I'd love to hear what=20
> you think about this.
As you want to inherit all the member functions from the underlying=20
class, it has a sens to concentrate on member functions. I don't=20
understand why friend functions could not follow the same schema.
>
>> As this is outside of the scope of my proposal, I did not include
>> this. And so, I cannot add to my proposal the conversion of
>> friend and non-member function when creating a copy-type. If this
>> could be included, there would be no problem for that.
> Sorry, I don't know yet what are type-aliases of methods.
>
>
> I'll try to explain myself better. A strong typedef of a function=20
> would be taking that function and replacing one or more types within=20
> it to others. You could say that when you do:
>
> template <typename T>
> void foo(T);
>
> then foo<int> and foo<double> are "strong typedefs" of each other, in=20
> some sense. If one were allowed to do this to existing code, one could=20
> do something like
>
> void foo(int);
>
> void foo(double) : using foo(int);
>
> to use an analogous syntax to the one in my proposal. Not sure if this=20
> is clearer, let me know.
I believe I understand you now but I don't see how this could help.
>
>> For example, consider
>>
>> struct A {};
>> struct B : using A {
>> operator A() =3D default;
>> };
>> struct C : using B {
>> operator B() =3D default;
>> operator A() =3D default;
>> };
>>
>> Just an idea.
> I'm lost.
>
>
> What I mean is, if B is a strong typedef of A, then we can default its=20
> conversion operator to A, right?
Right.
> But then, if C is a type-copy of B, then we can default its conversion=20
> operator to both B (since it's its type-copy),
Right
> and also to A (since C is a type-copy of a type-copy).
The first Opaque proposal contained a implicit subsumption relation that=20
allowed that. I'm all for, but I believe the committee doesn't like=20
transitivity in conversions.
>
>> Is it really wise to allow the compiler to be able to default
>> convert B to A?
> I would say, yes. The question p0109 raise is whether the user
> wants it.
>
>
> I'm not sure, however to me there's no difference either way.
The compiler is always able to do the conversion and the user defines=20
when the compiler will do it.
>
>> Maybe. I thought that inherited classes are also declared without
>> mentioning that they inherit, so I though that the same should
>> hold for copies.
> Maybe, but the C++ standard doesn't have constrains on whether the
> class is derived from another class.
>
>
> True. I'll try to think about this a bit more. Maybe we could simply=20
> lift the restriction and let the user do what he/she wants? (so also=20
> use classes that are not necessarily copies of the originals, as long=20
> as their interface is compatible to what it needs to be)
Maybe.
>
>> That's true, and that's mostly what I don't like about giving the
>> ability to modify copied existing methods. It is definitely
>> non-obvious that this is happening. If you make a mistake, it
>> will take a long time to figure out that you involuntarily
>> modified the behavior of the original class. That's bad in my book.
> Maybe you need something like override to state clearly that you
> want to redefine the inherited behavior.
>
>
> Unfortunately there would be nothing to override, as you are adding a=20
> new overload completely separate to the old one. Both would still be=20
> usable and work, nothing is being redefined. Simply the old function=20
> would get linked against the new implementation. There's nothing that=20
> the compiler could do to prevent this.
Well, this is your proposal, and if you don't want to be able to modify=20
the duplicate class, you are then right. But if you where able to modify=20
the duplicated class, overriden could have a sense, to mean replace it.
>
> Best,
> Eugenio
Vicente
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/9adc5a02-3209-bf63-a684-fb0272da56e0%40wanadoo.f=
r.
--------------89CEE71906F4E0C909D27C43
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 01/01/2017 =C3=A0 18:26, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<br>
Eugenio, I believe the use cases we have both in mind are quite
different, and so we don't reach to understand one to each other.<br>
<br>
I have a question. Does you copy class proposal needs to have the
definition of the copied class available?<br>
If yes, I don't think this could be acceptable.<br>
If the declaration is enough, the copied functions would need at
least an internal conversion to/from the underlying type, isn't it?<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Note that inheritance
allows you to make a member not accessible.<span
class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"> struct A {</span><br>
<span class=3D"gmail-im"> =C2=A0=C2=A0=C2=A0=C2=A0 int foo(int =
x) { return x * 2;
}</span><br>
<span class=3D"gmail-im"> =C2=A0=C2=A0=C2=A0=C2=A0 double bar(d=
ouble x) { return
foo(x) * 4.0; }</span><br>
<span class=3D"gmail-im"> };</span><br>
<span class=3D"gmail-im"> </span><br>
<span class=3D"gmail-im"></span> struct B : A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x)=
;<br>
};</blockquote>
<div><br>
</div>
<div>I assume that you wanted to use public inheritance. With
private inheritance being an equivalent of encapsulation,
the assertion would not be interesting, since wrapping of
course removes access to the encapsulated data. With public
inheritance, you did not make that member not accessible. It
is still so, you have just hidden it.<br>
<br>
B b;<br>
b.A::bar(5);<br>
<br>
</div>
</div>
</div>
</blockquote>
Agreed. And the language let me do that even if you find it could be
bad practice. I don't see why your copy approach wouldn't let me do
that.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>There is a difference. In addition, I don't believe that
two wrongs make a right. Making a feature that can be
potentially abused in the worst ways is not wise, I think.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">One of the
problems of your proposal is that the copied
class has access to the private members, which
is more subject to changes. I believe that the
copied class should only have access to public
members.</blockquote>
<div><br>
</div>
If one creates a new class, and private members
cannot be accessed, there will not be any way to
touch them to do anything else aside from the
original interface. </div>
</div>
</blockquote>
</span> Right.<span class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>This is also compounded by the fact that all
old methods accepting the original class won't
work on the new class (creating an operator Base()
should be an exception for certain use-cases, it
should not be necessary to do so). </div>
</div>
</blockquote>
</span> The Base conversion can be protected or private.
The trampoline would take care of this conversions.<span
class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How are you going to print a copy? </div>
</div>
</blockquote>
</span> Hmm, using the public interface or don't.<span
class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How can you convert in a custom way to the
original class?</div>
</div>
</blockquote>
</span> I don't see the use case. Maybe you have one.<span
class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div> How are you going to implement additional and
useful methods without access to privates?<br>
</div>
</div>
</blockquote>
</span> If we need to access to private I believe it is
worth creating a new class. </blockquote>
<div><br>
</div>
<div>If I understand correctly, you want to be able to
create a copy of another class, with the ability to alter
and access its public interface only. What happens when
you delete a public method used by a private method? </div>
</div>
</div>
</div>
</blockquote>
Compile error ?<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>What happens when you delete a public attribute used in
private code?</div>
</div>
</div>
</div>
</blockquote>
We can not remove data members, otherwise we can not share the same
representation.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> What happens to protected code - if not accessible you
basically make inheritance useless on it? </div>
</div>
</div>
</div>
</blockquote>
Good question. With the wrapping approach, you couldn't inherit from
it. With you approach, the data will be copied. The question is if
the strong-type has access to this protected data.<br>
I have never needed to create a duplicate of a class that is part of
inheritance hierarchy. I've always wrapped final classes. Some
examples will help me to clarify the need.<br>
I believe we could have duplication having access only to the public
part and let the derived classes use the protected part.
Nevertheless I could live providing access to the protected part.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>If in all these cases your answer is "the program will
fail to compile, just copy the class by hand" then I think
the feature would be severely limited in what it could
actually do.<br>
</div>
</div>
</div>
</div>
</blockquote>
You are probably right, and the copy should copy every thing and
give access to everything internally. I need some concrete examples
to understand what this possibility will solve.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>I feel that what you are proposing is basically a fast
way to create PIMPL wrappers.</div>
</div>
</div>
</div>
</blockquote>
Not at all.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> If I understand correctly, you want to hide the
original completely, and just be offered an easy way to
bring back some of its interface (via trampolines) to its
"wrapper", which would be the strong typedef. </div>
</div>
</div>
</div>
</blockquote>
I wouldn't say hiding, just don't looking inside the underlying
type. I want to provide access to it (when needed) but only as a
whole.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Possibly adding more public methods only using the
public interface, which could be done just the same with
non-member methods. The end result is a class that cannot
be extended in any meaningful way using any of the normal
C++ facilities, since every juicy bit is hidden. </div>
</div>
</div>
</div>
</blockquote>
Why it is unusable? The class provide access to everything you want.<br=
>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying inheritance to it would require manual
exposure of all methods, with the limitations we have
already discussed. </div>
</div>
</div>
</div>
</blockquote>
I don't follow you here.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying strong-typing again to a strong-typed class
would be useless as access to internals would be the same,
</div>
</div>
</div>
</div>
</blockquote>
You can strong-type again. I don't see the trouble. E.g; you can
have a energy strong-type and have kinetic_energy, potential_energy
and=C2=A0 heat_energy strong-type of energy.<br>
Typing and representation are two different things. Strong types are
just that. Share a representation and have different types.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>aside from possibly adding more data (if needed) in the
public attributes, since only those are editable. This
would also prevent encapsulation of new data. If not, it
would just mean that the feature wouldn't be used in a
composable way.<br>
</div>
</div>
</div>
</div>
</blockquote>
I believe now that strong-type shouldn't add any new non-static data
member.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>My own idea is to be able to extend an already existing
class into a new class. I may not have 100% use cases for
all things I'm proposing, but that is simply because I
can't write in advance all possible programs with the
feature. I just feel (maybe feeling is not enough, but
opinions are also made of these unfortunately) that if a
new feature has to be introduced it should at least try to
play ball with the rest of the language. The more it does,
the more it can be used in any weird case that may come
up. One of the most beautiful things about C++ is that
there's pretty much always a way to do something, exactly
because the language is flexible and its parts can be
combined in many possible ways. A feature that creates a
non-extendable object is like a dead-end.<br>
</div>
</div>
</div>
</div>
</blockquote>
I must agree with your last sentence, but I don't think the
strong-types I'm suggesting are non-extendable?<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">What I mean is that
these wrappers should be part of the proposal and show
how the your copy class reach to make concrete and real
opaque types as e.g the energy example in P0109.<span
class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span></blockquote>
<br>
</div>
<div>But wrappers can be made in a separate library. Why
should they be included in the proposal? As long as the
proposal allows them, a library only needs to be made once
(and if not needed by someone, not used).<br>
</div>
</div>
</div>
</div>
</blockquote>
We need some probe of concept applied to concrete examples we want
to solve. I believe a strong type feature must solve the builtin
type case. If your proposal is not a strong type proposal, then
forget my comments.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>You see that in order to have a custom type,
still many things must be written. So what's the
difference between creating copyable wrappers
(using normal C++ rules), and creating a number
of such interfaces (having to learn and teach
how protected/public/private work in a new
context)? I don't see what the difference would
be. Why do you feel that wrappers on primitive
types are not enough?<br>
</div>
</div>
</blockquote>
</span> Yes, the new opaque type must define all the
available functions. Note that p0109 provides
conversions and the possibility to request the compiler
to generate the default trampolines. This is much sorter
than defining them using the current C++ language.
Implicit conversions (public) allow to use the new
opaque type where the underlying type was expected. <br>
<br>
I would prefer the opaque type proposal to go even
further (or an independent proposal) and be able to
introduce groups of trampolines as I did on my Opaque
library with the combined mixins. However I have no
concrete proposal at the language level. <br>
</blockquote>
<div><br>
</div>
<div>But I have made you an example with wrappers, which
you also agreed is similar to what your library
currently does. So what is wrong with that approach? <br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I believe we are not understanding one each other. My two last
paragraphs don't concern your proposal. It concerns p0109.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>struct A {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
struct B : using A {};<br>
<br>
What will be the type of x<br>
<br>
B b1, b2;<br>
auto x =3D b1.append(b2);<br>
<br>
IIUC your proposal, the append function will be copied
replacing any occurrence of A by B, so it is as if B
was declared<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
Am I missing something? (***)<br>
<br>
Or would B equivalent to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(B const&);<br>
};<br>
<br>
or to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
I'm wondering now if the copied class could add at all
new non-static data members. Otherwise I don't see how
the duplication of such function can be done. I
suspect that p0109 doesn't allow to add new data.<br>
Then, if the user wants to add more data, it should
first duplicate the class and then inherit from the
duplicated class to add more data.<span
class=3D"gmail-im"><br>
</span></blockquote>
<br>
</div>
<div>No, you understood correctly, the end result would be
<br>
<br>
</div>
<div>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Great.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Forcing the user to inherit to add more data adds
inheritance, which means that types are now implicitly
convertible (to at least a common base). I don't think
this is desirable. I think strong typing should work on
its own.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
How then you will be able to construct a B from a A if B adds more
non-static data members?<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>In some sense creating a new foo overload
using the type-copy. However, I believe this
would be a pretty big change. </div>
</div>
</div>
</blockquote>
</span> I believed this was already part of your
proposal. (***)<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Mhh, now that you put it this way. I thought about
only doing this for classes. </div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Do you mean for member functions?<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>While the mechanism for free functions would be the
same (that's what I mean by strong-typedef of a
function, see below), the scope would be wider. One
only works for classes, the other on all free
functions. I don't know, maybe dividing them makes no
sense. I'd love to hear what you think about this.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
As you want to inherit all the member functions from the underlying
class, it has a sens to concentrate on member functions. I don't
understand why friend functions could not follow the same schema.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>As this is outside of the scope of my
proposal, I did not include this. And so,
I cannot add to my proposal the conversion
of friend and non-member function when
creating a copy-type. If this could be
included, there would be no problem for
that.<br>
</div>
</div>
</div>
</blockquote>
</span> Sorry, I don't know yet what are
type-aliases of methods. <br>
</blockquote>
<div><br>
</div>
<div>I'll try to explain myself better. A strong
typedef of a function would be taking that function
and replacing one or more types within it to others.
You could say that when you do:<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>void foo(T);<br>
<br>
</div>
<div>then foo<int> and foo<double> are
"strong typedefs" of each other, in some sense. If
one were allowed to do this to existing code, one
could do something like<br>
<br>
</div>
<div>void foo(int);<br>
<br>
</div>
<div>void foo(double) : using foo(int);<br>
<br>
</div>
<div>to use an analogous syntax to the one in my
proposal. Not sure if this is clearer, let me know.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
I believe I understand you now but I don't see how this could help.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>For example, consider<br>
<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D de=
fault;<br>
</div>
<div>};<br>
</div>
<div>struct C : using B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator B() =3D de=
fault;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D de=
fault;<br>
};<br>
<br>
</div>
<div>Just an idea.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I'm lost.<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>What I mean is, if B is a strong typedef of A,
then we can default its conversion operator to A,
right? </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Right.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>But then, if C is a type-copy of B, then we can
default its conversion operator to both B (since
it's its type-copy), </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Right<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>and also to A (since C is a type-copy of a
type-copy).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
The first Opaque proposal contained a implicit subsumption relation
that allowed that. I'm all for, but I believe the committee doesn't
like transitivity in conversions.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Is it really wise to allow the
compiler to be able to default
convert B to A? </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I would say, yes. The question p0109
raise is whether the user wants it.<span
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I'm not sure, however to me there's no
difference either way.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
The compiler is always able to do the conversion and the user
defines when the compiler will do it.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Maybe. I thought that
inherited classes are also
declared without mentioning that
they inherit, so I though that
the same should hold for copies.<br=
>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Maybe, but the C++ standard doesn't
have constrains on whether the class is
derived from another class.<span
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True. I'll try to think about this a bit
more. Maybe we could simply lift the
restriction and let the user do what he/she
wants? (so also use classes that are not
necessarily copies of the originals, as long
as their interface is compatible to what it
needs to be) <span class=3D"gmail-im"><br>
</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Maybe.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote"
style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>That's true, and that's
mostly what I don't like
about giving the ability to
modify copied existing
methods. It is definitely
non-obvious that this is
happening. If you make a
mistake, it will take a long
time to figure out that you
involuntarily modified the
behavior of the original
class. That's bad in my
book.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Maybe you need something like
override to state clearly that you want to
redefine the inherited behavior.<span
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Unfortunately there would be nothing to
override, as you are adding a new overload
completely separate to the old one. Both
would still be usable and work, nothing is
being redefined. Simply the old function
would get linked against the new
implementation. There's nothing that the
compiler could do to prevent this.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Well, this is your proposal, and if you don't want to be able to
modify the duplicate class, you are then right. But if you where
able to modify the duplicated class, overriden could have a sense,
to mean replace it.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tEbHpzdtK40qS_tVUPfPyKnOft-ZXOTMTDezPDzS3fAw@mail.gmai=
l.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Best,<br>
</div>
<div>Eugenio<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9adc5a02-3209-bf63-a684-fb0272da56e0%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/9adc5a02-3209-bf63-a684-fb0272da56e0=
%40wanadoo.fr</a>.<br />
--------------89CEE71906F4E0C909D27C43--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Mon, 2 Jan 2017 13:31:32 +0100
Raw View
--001a113dc5885ce22c05451bbbab
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vicente,
Eugenio, I believe the use cases we have both in mind are quite different,
> and so we don't reach to understand one to each other.
It seems so. I am available to try other forms of communications if you
want (chat, voice call) if you want. I'm sorry I'm not being as clear as I
want.
I have a question. Does you copy class proposal needs to have the
> definition of the copied class available?
> If yes, I don't think this could be acceptable.
> If the declaration is enough, the copied functions would need at least an
> internal conversion to/from the underlying type, isn't it?
>
My proposal does not need the definition. Yes, I suppose an internal
conversion would be needed. The internal conversion would probably work
similarly to how inheritance works, even if adding non-static members was
allowed. As in, the compiler knows that the first piece of the class will
be the same as the original, and every new member is added at the end.
> B b;
> b.A::bar(5);
>
> Agreed. And the language let me do that even if you find it could be bad
> practice. I don't see why your copy approach wouldn't let me do that.
>
In my approach the old function is impossible to hide, so I think that the
two cases are different.
> If in all these cases your answer is "the program will fail to compile,
> just copy the class by hand" then I think the feature would be severely
> limited in what it could actually do.
>
> You are probably right, and the copy should copy every thing and give
> access to everything internally. I need some concrete examples to
> understand what this possibility will solve.
>
Well, for example, a library that wanted to create strong typedefs of
primitive types via wrappers and only expose certain operations, without
getters/setters ;) I've added some code later to show you how a possible
implementation using this proposal.
> If I understand correctly, you want to hide the original completely, and
> just be offered an easy way to bring back some of its interface (via
> trampolines) to its "wrapper", which would be the strong typedef.
>
> I wouldn't say hiding, just don't looking inside the underlying type. I
> want to provide access to it (when needed) but only as a whole.
>
> Possibly adding more public methods only using the public interface, whic=
h
> could be done just the same with non-member methods. The end result is a
> class that cannot be extended in any meaningful way using any of the norm=
al
> C++ facilities, since every juicy bit is hidden.
>
> Why it is unusable? The class provide access to everything you want.
>
Classes don't always come with getters and setters for every private field.
Especially if the interface they provide is a high level one. It happens
often in low-level code that you want to interact with the underlying bits
in very specific ways, but you don't necessarily want to give that kind of
access to users. So creating a strong typedef of such a class while adding
a new mode of operation would be impossible, as the copy won't have access
to the underlying implementation.
Another could be when you have to types that you know contain the same
(private) data, but should expose different public interfaces. Then you
could first create the class containing the data, and copy it two times,
each time exposing a different interface (which would need access to the
private data). Once again, I unfortunately don't have a practical use case
at the moment. I just think it could be useful.
Still the code below is a good use-case I think, since it would be needed
to provide strong typedefs of primitive types.
> Applying strong-typing again to a strong-typed class would be useless as
> access to internals would be the same,
>
> You can strong-type again. I don't see the trouble. E.g; you can have a
> energy strong-type and have kinetic_energy, potential_energy and
> heat_energy strong-type of energy.
> Typing and representation are two different things. Strong types are just
> that. Share a representation and have different types.
>
Yes, of course. What I mean is, you have created a class which can only
create exact copies of it. If you need additional changes, it will probably
be easier to strong-type the original again and create new trampolines from
that. This is what I mean by non-extendable.
> aside from possibly adding more data (if needed) in the public attributes=
,
> since only those are editable. This would also prevent encapsulation of n=
ew
> data. If not, it would just mean that the feature wouldn't be used in a
> composable way.
>
> I believe now that strong-type shouldn't add any new non-static data memb=
er
I start to see what you mean. But still, if one could add them, the copy
would still "contain" an equivalent of the original class at its beginning.
It wouldn't be guaranteed reinterpret_cast-able, but the fields would be
there anyway. The original representation is there - so to me it could
still be considered a strong-typedef (stretching a bit the definition
maybe).
Is there any other reason why you don't like the idea?
> A feature that creates a non-extendable object is like a dead-end.
>
> I must agree with your last sentence, but I don't think the strong-types
> I'm suggesting are non-extendable?
>
Well, if only the public interface is available, than adding new methods to
it is pretty much equivalent with creating non-member functions (since
those work with public interface). Then you might as well remove the
ability to add new member functions, since non-members will do just fine
and there's no need to have them as members.
But wrappers can be made in a separate library. Why should they be included
> in the proposal? As long as the proposal allows them, a library only need=
s
> to be made once (and if not needed by someone, not used).
>
> We need some probe of concept applied to concrete examples we want to
> solve. I believe a strong type feature must solve the builtin type case. =
If
> your proposal is not a strong type proposal, then forget my comments.
>
This is how I would practically solve the primitive types problem using my
proposal:
------------------------------------------
// library.hpp
template <typename T>
class Wrap {
public:
using base_type =3D T;
Wrap(const Wrap & other) : t_(other.t_) {}
explicit Wrap(T t) : t_(t) {}
private:
T t_;
};
template <typename C>
class ConvertBack : using C {
operator base_type() { return t_; }
};
template <typename C>
class Plus : using C {
Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
};
template <typename C>
class Minus : using C {
Minus operator-(Minus other) { return Minus{t_ - other.t_}; }
};
template <typename C>
class Prod : using C {
Prod operator+(Prod other) { return Prod{t_ * other.t_}; }
};
template <typename C>
class Div : using C {
Div operator/(Div other) { return Div{t_ / other.t_}; }
};
template <typename T>
using Arithmetic =3D Div<Prod<Minus<Plus<Wrap<T>>>>>;
// .... and so on
// usercode.cpp
#include "library.hpp"
// Strong typedef of int with +,-,/,*
struct MyInt : using Arithmetic<int> {}
// Strong typedef of double with +,- convertible to double
struct MyDouble : using ConvertBack<Minus<Plus<Wrap<double>>>> {}
--------------------------------------------
If there's something missing you'd like to see how I'd do, let me know. Of
course verbosity depends on granularity. If all operations need to be
manually selected you'll have lots of classes. If the granularity required
is less each class could add more operators at once.
Note that you need access to privates to be able to do this, so this could
be an use-case for that.
A problem that is not tackled in this code and that we are also discussing
is what to do with non-member functions (that could possibly take base_type
as input). That depends on how non-member functions will be handled in the
proposals. If they can be handled I would actually be happier.
Forcing the user to inherit to add more data adds inheritance, which means
> that types are now implicitly convertible (to at least a common base). I
> don't think this is desirable. I think strong typing should work on its o=
wn.
>
> How then you will be able to construct a B from a A if B adds more
> non-static data members?
>
One option is to simply define a constructor in B which takes A. Otherwise,
it would be the same case when you create a class with a member which the
constructor does not initialize. Otherwise one exception could be made for
constructors so that they can be redefined in the new class. This probably
makes sense and it shoudn't be possible to break something (unless one
creates a constructor which does not initialize some fields which are
assumed initialized by the original class.. but then I believe it's a
reasonable risk).
As you want to inherit all the member functions from the underlying class,
> it has a sens to concentrate on member functions. I don't understand why
> friend functions could not follow the same schema.
>
Well, friend functions are not members, so if you allow copying them, you
are allowing copying arbitrary non-member functions (which I approve of).
The only problem with this is that it is a big change - on top of this
proposal. Just that.
void foo(int);
>
> void foo(double) : using foo(int);
>
> to use an analogous syntax to the one in my proposal. Not sure if this is
> clearer, let me know.
>
> I believe I understand you now but I don't see how this could help.
>
Well, this would be the way to create the "trampolines" for non-member
functions. When you copy a class, you specify just once from which class
you are copying. The compiler can then apply the change to all member
functions automatically.
However, you still have to specify non-member functions manually, since the
compiler cannot assume you want them all.
and also to A (since C is a type-copy of a type-copy).
>
> The first Opaque proposal contained a implicit subsumption relation that
> allowed that. I'm all for, but I believe the committee doesn't like
> transitivity in conversions.
>
Well, it is not really transitivity. As in, the C to A transition does not
need an implicit transition from B. The user is explicitly creating the
conversion operator. The data in C exists, so it can be copied directly.
Maybe you mean transitivity in the sense that the compiler needs to
remember that C is a copy of B in order for it to know that it is also a
copy of A. In that case I agree.
In any case, I don't think it is really necessary, it was just an idea.
Best,
Eugenio Bargiacchi
On Mon, Jan 2, 2017 at 12:30 AM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 01/01/2017 =C3=A0 18:26, Eugenio Bargiacchi a =C3=A9crit :
>
> Eugenio, I believe the use cases we have both in mind are quite different=
,
> and so we don't reach to understand one to each other.
>
> I have a question. Does you copy class proposal needs to have the
> definition of the copied class available?
> If yes, I don't think this could be acceptable.
> If the declaration is enough, the copied functions would need at least an
> internal conversion to/from the underlying type, isn't it?
>
>
> Note that inheritance allows you to make a member not accessible.
>> struct A {
>> int foo(int x) { return x * 2; }
>> double bar(double x) { return foo(x) * 4.0; }
>> };
>>
>> struct B : A {
>> private:
>> double bar(double x);
>> };
>
>
> I assume that you wanted to use public inheritance. With private
> inheritance being an equivalent of encapsulation, the assertion would not
> be interesting, since wrapping of course removes access to the encapsulat=
ed
> data. With public inheritance, you did not make that member not accessibl=
e.
> It is still so, you have just hidden it.
>
> B b;
> b.A::bar(5);
>
> Agreed. And the language let me do that even if you find it could be bad
> practice. I don't see why your copy approach wouldn't let me do that.
>
> There is a difference. In addition, I don't believe that two wrongs make =
a
> right. Making a feature that can be potentially abused in the worst ways =
is
> not wise, I think.
>
> One of the problems of your proposal is that the copied class has access
>>> to the private members, which is more subject to changes. I believe tha=
t
>>> the copied class should only have access to public members.
>>
>>
>> If one creates a new class, and private members cannot be accessed, ther=
e
>> will not be any way to touch them to do anything else aside from the
>> original interface.
>>
>> Right.
>>
>> This is also compounded by the fact that all old methods accepting the
>> original class won't work on the new class (creating an operator Base()
>> should be an exception for certain use-cases, it should not be necessary=
to
>> do so).
>>
>> The Base conversion can be protected or private. The trampoline would
>> take care of this conversions.
>>
>> How are you going to print a copy?
>>
>> Hmm, using the public interface or don't.
>>
>> How can you convert in a custom way to the original class?
>>
>> I don't see the use case. Maybe you have one.
>>
>> How are you going to implement additional and useful methods without
>> access to privates?
>>
>> If we need to access to private I believe it is worth creating a new
>> class.
>
>
> If I understand correctly, you want to be able to create a copy of anothe=
r
> class, with the ability to alter and access its public interface only. Wh=
at
> happens when you delete a public method used by a private method?
>
> Compile error ?
>
> What happens when you delete a public attribute used in private code?
>
> We can not remove data members, otherwise we can not share the same
> representation.
>
> What happens to protected code - if not accessible you basically make
> inheritance useless on it?
>
> Good question. With the wrapping approach, you couldn't inherit from it.
> With you approach, the data will be copied. The question is if the
> strong-type has access to this protected data.
> I have never needed to create a duplicate of a class that is part of
> inheritance hierarchy. I've always wrapped final classes. Some examples
> will help me to clarify the need.
> I believe we could have duplication having access only to the public part
> and let the derived classes use the protected part. Nevertheless I could
> live providing access to the protected part.
>
> If in all these cases your answer is "the program will fail to compile,
> just copy the class by hand" then I think the feature would be severely
> limited in what it could actually do.
>
> You are probably right, and the copy should copy every thing and give
> access to everything internally. I need some concrete examples to
> understand what this possibility will solve.
>
>
> I feel that what you are proposing is basically a fast way to create PIMP=
L
> wrappers.
>
> Not at all.
>
> If I understand correctly, you want to hide the original completely, and
> just be offered an easy way to bring back some of its interface (via
> trampolines) to its "wrapper", which would be the strong typedef.
>
> I wouldn't say hiding, just don't looking inside the underlying type. I
> want to provide access to it (when needed) but only as a whole.
>
> Possibly adding more public methods only using the public interface, whic=
h
> could be done just the same with non-member methods. The end result is a
> class that cannot be extended in any meaningful way using any of the norm=
al
> C++ facilities, since every juicy bit is hidden.
>
> Why it is unusable? The class provide access to everything you want.
>
> Applying inheritance to it would require manual exposure of all methods,
> with the limitations we have already discussed.
>
> I don't follow you here.
>
> Applying strong-typing again to a strong-typed class would be useless as
> access to internals would be the same,
>
> You can strong-type again. I don't see the trouble. E.g; you can have a
> energy strong-type and have kinetic_energy, potential_energy and
> heat_energy strong-type of energy.
> Typing and representation are two different things. Strong types are just
> that. Share a representation and have different types.
>
> aside from possibly adding more data (if needed) in the public attributes=
,
> since only those are editable. This would also prevent encapsulation of n=
ew
> data. If not, it would just mean that the feature wouldn't be used in a
> composable way.
>
> I believe now that strong-type shouldn't add any new non-static data
> member.
>
>
> My own idea is to be able to extend an already existing class into a new
> class. I may not have 100% use cases for all things I'm proposing, but th=
at
> is simply because I can't write in advance all possible programs with the
> feature. I just feel (maybe feeling is not enough, but opinions are also
> made of these unfortunately) that if a new feature has to be introduced i=
t
> should at least try to play ball with the rest of the language. The more =
it
> does, the more it can be used in any weird case that may come up. One of
> the most beautiful things about C++ is that there's pretty much always a
> way to do something, exactly because the language is flexible and its par=
ts
> can be combined in many possible ways. A feature that creates a
> non-extendable object is like a dead-end.
>
> I must agree with your last sentence, but I don't think the strong-types
> I'm suggesting are non-extendable?
>
>
> What I mean is that these wrappers should be part of the proposal and sho=
w
>> how the your copy class reach to make concrete and real opaque types as =
e.g
>> the energy example in P0109.
>>
>
> But wrappers can be made in a separate library. Why should they be
> included in the proposal? As long as the proposal allows them, a library
> only needs to be made once (and if not needed by someone, not used).
>
> We need some probe of concept applied to concrete examples we want to
> solve. I believe a strong type feature must solve the builtin type case. =
If
> your proposal is not a strong type proposal, then forget my comments.
>
> You see that in order to have a custom type, still many things must be
>> written. So what's the difference between creating copyable wrappers (us=
ing
>> normal C++ rules), and creating a number of such interfaces (having to
>> learn and teach how protected/public/private work in a new context)? I
>> don't see what the difference would be. Why do you feel that wrappers on
>> primitive types are not enough?
>>
>> Yes, the new opaque type must define all the available functions. Note
>> that p0109 provides conversions and the possibility to request the compi=
ler
>> to generate the default trampolines. This is much sorter than defining t=
hem
>> using the current C++ language. Implicit conversions (public) allow to u=
se
>> the new opaque type where the underlying type was expected.
>>
>> I would prefer the opaque type proposal to go even further (or an
>> independent proposal) and be able to introduce groups of trampolines as =
I
>> did on my Opaque library with the combined mixins. However I have no
>> concrete proposal at the language level.
>>
>
> But I have made you an example with wrappers, which you also agreed is
> similar to what your library currently does. So what is wrong with that
> approach?
>
> I believe we are not understanding one each other. My two last paragraphs
> don't concern your proposal. It concerns p0109.
>
>
> struct A {
>> A append(A const&);
>> };
>>
>> struct B : using A {};
>>
>> What will be the type of x
>>
>> B b1, b2;
>> auto x =3D b1.append(b2);
>>
>> IIUC your proposal, the append function will be copied replacing any
>> occurrence of A by B, so it is as if B was declared
>>
>> struct B {
>> B append(B const&);
>> };
>>
>> Am I missing something? (***)
>>
>> Or would B equivalent to
>>
>> struct B {
>> A append(B const&);
>> };
>>
>> or to
>>
>> struct B {
>> A append(A const&);
>> };
>>
>> I'm wondering now if the copied class could add at all new non-static
>> data members. Otherwise I don't see how the duplication of such function
>> can be done. I suspect that p0109 doesn't allow to add new data.
>> Then, if the user wants to add more data, it should first duplicate the
>> class and then inherit from the duplicated class to add more data.
>>
>
> No, you understood correctly, the end result would be
>
> struct B {
> B append(B const&);
> };
>
> Great.
>
> Forcing the user to inherit to add more data adds inheritance, which mean=
s
> that types are now implicitly convertible (to at least a common base). I
> don't think this is desirable. I think strong typing should work on its o=
wn.
>
> How then you will be able to construct a B from a A if B adds more
> non-static data members?
>
>
> In some sense creating a new foo overload using the type-copy. However, I
>> believe this would be a pretty big change.
>>
>> I believed this was already part of your proposal. (***)
>>
>
> Mhh, now that you put it this way. I thought about only doing this for
> classes.
>
> Do you mean for member functions?
>
> While the mechanism for free functions would be the same (that's what I
> mean by strong-typedef of a function, see below), the scope would be wide=
r.
> One only works for classes, the other on all free functions. I don't know=
,
> maybe dividing them makes no sense. I'd love to hear what you think about
> this.
>
> As you want to inherit all the member functions from the underlying class=
,
> it has a sens to concentrate on member functions. I don't understand why
> friend functions could not follow the same schema.
>
> As this is outside of the scope of my proposal, I did not include this.
>> And so, I cannot add to my proposal the conversion of friend and non-mem=
ber
>> function when creating a copy-type. If this could be included, there wou=
ld
>> be no problem for that.
>>
>> Sorry, I don't know yet what are type-aliases of methods.
>>
>
> I'll try to explain myself better. A strong typedef of a function would b=
e
> taking that function and replacing one or more types within it to others.
> You could say that when you do:
>
> template <typename T>
> void foo(T);
>
> then foo<int> and foo<double> are "strong typedefs" of each other, in som=
e
> sense. If one were allowed to do this to existing code, one could do
> something like
>
> void foo(int);
>
> void foo(double) : using foo(int);
>
> to use an analogous syntax to the one in my proposal. Not sure if this is
> clearer, let me know.
>
> I believe I understand you now but I don't see how this could help.
>
> For example, consider
>>
>> struct A {};
>> struct B : using A {
>> operator A() =3D default;
>> };
>> struct C : using B {
>> operator B() =3D default;
>> operator A() =3D default;
>> };
>>
>> Just an idea.
>>
>> I'm lost.
>>
>
> What I mean is, if B is a strong typedef of A, then we can default its
> conversion operator to A, right?
>
> Right.
>
> But then, if C is a type-copy of B, then we can default its conversion
> operator to both B (since it's its type-copy),
>
> Right
>
> and also to A (since C is a type-copy of a type-copy).
>
> The first Opaque proposal contained a implicit subsumption relation that
> allowed that. I'm all for, but I believe the committee doesn't like
> transitivity in conversions.
>
>
> Is it really wise to allow the compiler to be able to default convert B t=
o
>> A?
>>
>> I would say, yes. The question p0109 raise is whether the user wants it.
>>
>
> I'm not sure, however to me there's no difference either way.
>
> The compiler is always able to do the conversion and the user defines whe=
n
> the compiler will do it.
>
>
> Maybe. I thought that inherited classes are also declared without
>> mentioning that they inherit, so I though that the same should hold for
>> copies.
>>
>> Maybe, but the C++ standard doesn't have constrains on whether the class
>> is derived from another class.
>>
>
> True. I'll try to think about this a bit more. Maybe we could simply lift
> the restriction and let the user do what he/she wants? (so also use class=
es
> that are not necessarily copies of the originals, as long as their
> interface is compatible to what it needs to be)
>
> Maybe.
>
> That's true, and that's mostly what I don't like about giving the ability
>> to modify copied existing methods. It is definitely non-obvious that thi=
s
>> is happening. If you make a mistake, it will take a long time to figure =
out
>> that you involuntarily modified the behavior of the original class. That=
's
>> bad in my book.
>>
>> Maybe you need something like override to state clearly that you want to
>> redefine the inherited behavior.
>>
>
> Unfortunately there would be nothing to override, as you are adding a new
> overload completely separate to the old one. Both would still be usable a=
nd
> work, nothing is being redefined. Simply the old function would get linke=
d
> against the new implementation. There's nothing that the compiler could d=
o
> to prevent this.
>
> Well, this is your proposal, and if you don't want to be able to modify
> the duplicate class, you are then right. But if you where able to modify
> the duplicated class, overriden could have a sense, to mean replace it.
>
>
> Best,
> Eugenio
>
> Vicente
>
> --
> 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/is
> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/is
> ocpp.org/d/msgid/std-proposals/9adc5a02-3209-bf63-a684-
> fb0272da56e0%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/9adc5a02-32=
09-bf63-a684-fb0272da56e0%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BvZEjYakroOWxB8u%2BSCS%3D5uDGU5mdYpWpy=
CbD-qS-P3TQ%40mail.gmail.com.
--001a113dc5885ce22c05451bbbab
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Dear Vicente,<br><br><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex">Eugenio, I believe the use cases we have both in mind are quit=
e
different, and so we don't reach to understand one to each other.</=
blockquote><div><br></div><div>It seems so. I am available to try other for=
ms of communications if you want (chat, voice call) if you want. I'm so=
rry I'm not being as clear as I want.<br><br><blockquote class=3D"gmail=
_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204=
,204);padding-left:1ex">I have a question. Does you copy class proposal nee=
ds to have the
definition of the copied class available?<br>
If yes, I don't think this could be acceptable.<br>
If the declaration is enough, the copied functions would need at
least an internal conversion to/from the underlying type, isn't it?=
<span class=3D"gmail-m_-1377447551499369339gmail-im"><br></span></blockquot=
e><div><br></div><div>My proposal does not need the definition. Yes, I supp=
ose an internal conversion would be needed. The internal conversion would p=
robably work similarly to how inheritance works, even if adding non-static =
members was allowed. As in, the compiler knows that the first piece of the =
class will be the same as the original, and every new member is added at th=
e end.<span class=3D"gmail-m_-1377447551499369339gmail-im"><br></span><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-m_-137744=
7551499369339gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><div=
>B b;<br>
b.A::bar(5);<br>
<br>
</div>
</div>
</div>
</blockquote></span>
Agreed. And the language let me do that even if you find it could be
bad practice. I don't see why your copy approach wouldn't let m=
e do
that.<span class=3D"gmail-m_-1377447551499369339gmail-im"><br></span></=
blockquote><div><br></div><div>In my approach the old function is impossibl=
e to hide, so I think that the two cases are different.<br><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid r=
gb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=
=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>If in all these cases your answer is "the program wil=
l
fail to compile, just copy the class by hand" then I thi=
nk
the feature would be severely limited in what it could
actually do.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
You are probably right, and the copy should copy every thing and
give access to everything internally. I need some concrete examples
to understand what this possibility will solve.<span class=3D"gmail-im"=
><br></span></blockquote><div><br></div><div>Well, for example, a library t=
hat wanted to create strong typedefs of primitive types via wrappers and on=
ly expose certain operations, without getters/setters ;) I've added som=
e code later to show you how a possible implementation using this proposal.=
<br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-=
im"><blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> If I understand correctly, you want to hide the
original completely, and just be offered an easy way to
bring back some of its interface (via trampolines) to its
"wrapper", which would be the strong typedef. </div=
>
</div>
</div>
</div>
</blockquote></span>
I wouldn't say hiding, just don't looking inside the underlying
type. I want to provide access to it (when needed) but only as a
whole.<span class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Possibly adding more public methods only using the
public interface, which could be done just the same with
non-member methods. The end result is a class that cannot
be extended in any meaningful way using any of the normal
C++ facilities, since every juicy bit is hidden. </div>
</div>
</div>
</div>
</blockquote></span>
Why it is unusable? The class provide access to everything you want.<sp=
an class=3D"gmail-im"><br></span></blockquote><div><br></div><div>Classes d=
on't always come with getters and setters for every private field. Espe=
cially if the interface they provide is a high level one. It happens often =
in low-level code that you want to interact with the underlying bits in ver=
y specific ways, but you don't necessarily want to give that kind of ac=
cess to users. So creating a strong typedef of such a class while adding a =
new mode of operation would be impossible, as the copy won't have acces=
s to the underlying implementation.<br><br>Another could be when you have t=
o types that you know contain the same (private) data, but should expose di=
fferent public interfaces. Then you could first create the class containing=
the data, and copy it two times, each time exposing a different interface =
(which would need access to the private data). Once again, I unfortunately =
don't have a practical use case at the moment. I just think it could be=
useful.<br><br></div><div>Still the code below is a good use-case I think,=
since it would be needed to provide strong typedefs of primitive types.<br=
></div><div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"gmail-im"><blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying strong-typing again to a strong-typed class
would be useless as access to internals would be the same,
</div>
</div>
</div>
</div>
</blockquote></span>
You can strong-type again. I don't see the trouble. E.g; you can
have a energy strong-type and have kinetic_energy, potential_energy
and=C2=A0 heat_energy strong-type of energy.<br>
Typing and representation are two different things. Strong types are
just that. Share a representation and have different types.<span class=
=3D"gmail-im"><br></span></blockquote></div></div></div> <br></div><div>Yes=
, of course. What I mean is, you have created a class which can only create=
exact copies of it. If you need additional changes, it will probably be ea=
sier to strong-type the original again and create new trampolines from that=
.. This is what I mean by non-extendable.<br><blockquote class=3D"gmail_quot=
e" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204)=
;padding-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>aside from possibly adding more data (if needed) in the
public attributes, since only those are editable. This
would also prevent encapsulation of new data. If not, it
would just mean that the feature wouldn't be used in a
composable way.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe now that strong-type shouldn't add any new non-static dat=
a
member</blockquote><div><br></div><div>I start to see what you mean. Bu=
t still, if one could add them, the copy would still "contain" an=
equivalent of the original class at its beginning. It wouldn't be guar=
anteed reinterpret_cast-able, but the fields would be there anyway. The ori=
ginal representation is there - so to me it could still be considered a str=
ong-typedef (stretching a bit the definition maybe).<br><br></div><div>Is t=
here any other reason why you don't like the idea?<br></div><div><block=
quote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1=
px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><block=
quote type=3D"cite"><div dir=3D"ltr"><div><div><div>A feature that creates =
a
non-extendable object is like a dead-end.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I must agree with your last sentence, but I don't think the
strong-types I'm suggesting are non-extendable?<span class=3D"gmail=
-im"></span> <br></blockquote></div><div><br></div><div>Well, if only the p=
ublic interface is available, than adding new methods to it is pretty much =
equivalent with creating non-member functions (since those work with public=
interface). Then you might as well remove the ability to add new member fu=
nctions, since non-members will do just fine and there's no need to hav=
e them as members.<br><br><blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><=
div><div>But wrappers can be made in a separate library. Why
should they be included in the proposal? As long as the
proposal allows them, a library only needs to be made once
(and if not needed by someone, not used).<br>
</div>
</div>
</div>
</div>
</blockquote></span>
We need some probe of concept applied to concrete examples we want
to solve. I believe a strong type feature must solve the builtin
type case. If your proposal is not a strong type proposal, then
forget my comments.<span class=3D"gmail-im"><br></span></blockquote></d=
iv><div><span class=3D"gmail-im"></span><br></div><div>This is how I would =
practically solve the primitive types problem using my proposal:<br><br>---=
---------------------------------------<br><br>// library.hpp<br><br>templa=
te <typename T><br>class Wrap {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 using base_type =3D T;<br><br>=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Wrap(const Wrap & other) : t_(o=
ther.t_) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 explicit Wrap(T t=
) : t_(t) {}<br>=C2=A0=C2=A0=C2=A0 <br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br>};<br><br>template <typ=
ename C><br>class ConvertBack : using C {<br>=C2=A0=C2=A0=C2=A0 operator=
base_type() { return t_; }<br>};<br><br>template <typename C><br>cla=
ss Plus : using C {<br>=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { retu=
rn Plus{t_ + other.t_}; }<br>};<br><br>template <typename C><br>class=
Minus : using C {<br>=C2=A0=C2=A0=C2=A0 Minus operator-(Minus other) { ret=
urn Minus{t_ - other.t_}; }<br>};<br><br>template <typename C><br>cla=
ss Prod : using C {<br>=C2=A0=C2=A0=C2=A0 Prod operator+(Prod other) { retu=
rn Prod{t_ * other.t_}; }<br>};<br><br>template <typename C><br>class=
Div : using C {<br>=C2=A0=C2=A0=C2=A0 Div operator/(Div other) { return Di=
v{t_ / other.t_}; }<br>};<br><br>template <typename T><br>using Arith=
metic =3D Div<Prod<Minus<Plus<Wrap<T>>>>>;<br=
><br>// .... and so on<br><br>// usercode.cpp<br><br>#include "library=
..hpp"<br><br> // Strong typedef of int with +,-,/,*<br>struct MyInt : =
using Arithmetic<int> {}<br><br>// Strong typedef of double with +,- =
convertible to double<br>struct MyDouble : using ConvertBack<Minus<Pl=
us<Wrap<double>>>> {}<br><br>----------------------------=
----------------</div></div></div><div class=3D"gmail_extra"><br></div><div=
class=3D"gmail_extra">If there's something missing you'd like to s=
ee how I'd do, let me know. Of course verbosity depends on granularity.=
If all operations need to be manually selected you'll have lots of cla=
sses. If the granularity required is less each class could add more operato=
rs at once.<br><br></div><div class=3D"gmail_extra">Note that you need acce=
ss to privates to be able to do this, so this could be an use-case for that=
..<br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">=
A problem that is not tackled in this code and that we are also discussing =
is what to do with non-member functions (that could possibly take base_type=
as input). That depends on how non-member functions will be handled in the=
proposals. If they can be handled I would actually be happier.<br><br><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left=
:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><blo=
ckquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Forcing the user to inherit to add more data adds
inheritance, which means that types are now implicitly
convertible (to at least a common base). I don't think
this is desirable. I think strong typing should work on
its own.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
How then you will be able to construct a B from a A if B adds more
non-static data members?<span class=3D"gmail-im"><br></span></blockquot=
e></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">One=
option is to simply define a constructor in B which takes A. Otherwise, it=
would be the same case when you create a class with a member which the con=
structor does not initialize. Otherwise one exception could be made for con=
structors so that they can be redefined in the new class. This probably mak=
es sense and it shoudn't be possible to break something (unless one cre=
ates a constructor which does not initialize some fields which are assumed =
initialized by the original class.. but then I believe it's a reasonabl=
e risk).<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">As you wa=
nt to inherit all the member functions from the underlying
class, it has a sens to concentrate on member functions. I don't
understand why friend functions could not follow the same schema.<span =
class=3D"gmail-im"><br></span></blockquote><div><br></div><div>Well, friend=
functions are not members, so if you allow copying them, you are allowing =
copying arbitrary non-member functions (which I approve of). The only probl=
em with this is that it is a big change - on top of this proposal. Just tha=
t.<br><span class=3D"gmail-im"><br></span><span class=3D"gmail-im"></span><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><=
blockquote type=3D"cite"><div dir=3D"ltr"><div><div><div><div><div><div>voi=
d foo(int);<br>
<br>
</div>
<div>void foo(double) : using foo(int);<br>
<br>
</div>
<div>to use an analogous syntax to the one in my
proposal. Not sure if this is clearer, let me know.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe I understand you now but I don't see how this could help.=
<span class=3D"gmail-im"><br></span></blockquote>=C2=A0</div></div><div cla=
ss=3D"gmail_extra">Well, this would be the way to create the "trampoli=
nes" for non-member functions. When you copy a class, you specify just=
once from which class you are copying. The compiler can then apply the cha=
nge to all member functions automatically.<br><br>However, you still have t=
o specify non-member functions manually, since the compiler cannot assume y=
ou want them all.<br><span class=3D"gmail-im"><br></span><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=
=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>and also to A (since C is a type-copy of a
type-copy).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
The first Opaque proposal contained a implicit subsumption relation
that allowed that. I'm all for, but I believe the committee doesn&#=
39;t
like transitivity in conversions.<span class=3D"gmail-im"><br></span></=
blockquote><br></div><div class=3D"gmail_extra">Well, it is not really tran=
sitivity. As in, the C to A transition does not need an implicit transition=
from B. The user is explicitly creating the conversion operator. The data =
in C exists, so it can be copied directly. Maybe you mean transitivity in t=
he sense that the compiler needs to remember that C is a copy of B in order=
for it to know that it is also a copy of A. In that case I agree.<br><br>I=
n any case, I don't think it is really necessary, it was just an idea.<=
br><br></div><div class=3D"gmail_extra">Best,<br></div><div class=3D"gmail_=
extra">Eugenio Bargiacchi<br></div><div class=3D"gmail_extra"><br></div><di=
v class=3D"gmail_extra"><div class=3D"gmail_quote">On Mon, Jan 2, 2017 at 1=
2:30 AM, Vicente J. Botet Escriba <span dir=3D"ltr"><<a href=3D"mailto:v=
icente.botet@wanadoo.fr" target=3D"_blank">vicente.botet@wanadoo.fr</a>>=
</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF">
<div class=3D"gmail-m_-1377447551499369339m_-4564586323290602189moz-cit=
e-prefix">Le 01/01/2017 =C3=A0 18:26, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<br>
Eugenio, I believe the use cases we have both in mind are quite
different, and so we don't reach to understand one to each other.<b=
r>
<br>
I have a question. Does you copy class proposal needs to have the
definition of the copied class available?<br>
If yes, I don't think this could be acceptable.<br>
If the declaration is enough, the copied functions would need at
least an internal conversion to/from the underlying type, isn't it?=
<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Note that inher=
itance
allows you to make a member not accessible.<span class=3D"gmail=
-m_-1377447551499369339m_-4564586323290602189gmail-im"></span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"> struct A {</span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"> =C2=A0=C2=A0=C2=A0=C2=A0 int foo(int x) { return x * 2;
}</span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"> =C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x) { return
foo(x) * 4.0; }</span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"> };</span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"> </span><br>
<span class=3D"gmail-m_-1377447551499369339m_-45645863232906021=
89gmail-im"></span> struct B : A {<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double bar(double x)=
;<br>
};</blockquote>
<div><br>
</div>
<div>I assume that you wanted to use public inheritance. With
private inheritance being an equivalent of encapsulation,
the assertion would not be interesting, since wrapping of
course removes access to the encapsulated data. With public
inheritance, you did not make that member not accessible. It
is still so, you have just hidden it.<br>
<br>
B b;<br>
b.A::bar(5);<br>
<br>
</div>
</div>
</div>
</blockquote></span>
Agreed. And the language let me do that even if you find it could be
bad practice. I don't see why your copy approach wouldn't let m=
e do
that.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>There is a difference. In addition, I don't believe that
two wrongs make a right. Making a feature that can be
potentially abused in the worst ways is not wise, I think.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One=
of the
problems of your proposal is that the copied
class has access to the private members, which
is more subject to changes. I believe that the
copied class should only have access to public
members.</blockquote>
<div><br>
</div>
If one creates a new class, and private members
cannot be accessed, there will not be any way to
touch them to do anything else aside from the
original interface. </div>
</div>
</blockquote>
</span> Right.<span class=3D"gmail-m_-1377447551499369339m_-4=
564586323290602189gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>This is also compounded by the fact that all
old methods accepting the original class won't
work on the new class (creating an operator Base()
should be an exception for certain use-cases, it
should not be necessary to do so). </div>
</div>
</blockquote>
</span> The Base conversion can be protected or private.
The trampoline would take care of this conversions.<span clas=
s=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How are you going to print a copy? </div>
</div>
</blockquote>
</span> Hmm, using the public interface or don't.<span cl=
ass=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>How can you convert in a custom way to the
original class?</div>
</div>
</blockquote>
</span> I don't see the use case. Maybe you have one.<spa=
n class=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div> How are you going to implement additional and
useful methods without access to privates?<br>
</div>
</div>
</blockquote>
</span> If we need to access to private I believe it is
worth creating a new class. </blockquote>
<div><br>
</div>
<div>If I understand correctly, you want to be able to
create a copy of another class, with the ability to alter
and access its public interface only. What happens when
you delete a public method used by a private method? </div>
</div>
</div>
</div>
</blockquote></span>
Compile error ?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>What happens when you delete a public attribute used in
private code?</div>
</div>
</div>
</div>
</blockquote></span>
We can not remove data members, otherwise we can not share the same
representation.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> What happens to protected code - if not accessible you
basically make inheritance useless on it? </div>
</div>
</div>
</div>
</blockquote></span>
Good question. With the wrapping approach, you couldn't inherit fro=
m
it. With you approach, the data will be copied. The question is if
the strong-type has access to this protected data.<br>
I have never needed to create a duplicate of a class that is part of
inheritance hierarchy. I've always wrapped final classes. Some
examples will help me to clarify the need.<br>
I believe we could have duplication having access only to the public
part and let the derived classes use the protected part.
Nevertheless I could live providing access to the protected part.<span>=
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>If in all these cases your answer is "the program wil=
l
fail to compile, just copy the class by hand" then I thi=
nk
the feature would be severely limited in what it could
actually do.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
You are probably right, and the copy should copy every thing and
give access to everything internally. I need some concrete examples
to understand what this possibility will solve.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>I feel that what you are proposing is basically a fast
way to create PIMPL wrappers.</div>
</div>
</div>
</div>
</blockquote></span>
Not at all.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> If I understand correctly, you want to hide the
original completely, and just be offered an easy way to
bring back some of its interface (via trampolines) to its
"wrapper", which would be the strong typedef. </div=
>
</div>
</div>
</div>
</blockquote></span>
I wouldn't say hiding, just don't looking inside the underlying
type. I want to provide access to it (when needed) but only as a
whole.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Possibly adding more public methods only using the
public interface, which could be done just the same with
non-member methods. The end result is a class that cannot
be extended in any meaningful way using any of the normal
C++ facilities, since every juicy bit is hidden. </div>
</div>
</div>
</div>
</blockquote></span>
Why it is unusable? The class provide access to everything you want.<sp=
an><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying inheritance to it would require manual
exposure of all methods, with the limitations we have
already discussed. </div>
</div>
</div>
</div>
</blockquote></span>
I don't follow you here.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying strong-typing again to a strong-typed class
would be useless as access to internals would be the same,
</div>
</div>
</div>
</div>
</blockquote></span>
You can strong-type again. I don't see the trouble. E.g; you can
have a energy strong-type and have kinetic_energy, potential_energy
and=C2=A0 heat_energy strong-type of energy.<br>
Typing and representation are two different things. Strong types are
just that. Share a representation and have different types.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>aside from possibly adding more data (if needed) in the
public attributes, since only those are editable. This
would also prevent encapsulation of new data. If not, it
would just mean that the feature wouldn't be used in a
composable way.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe now that strong-type shouldn't add any new non-static dat=
a
member.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>My own idea is to be able to extend an already existing
class into a new class. I may not have 100% use cases for
all things I'm proposing, but that is simply because I
can't write in advance all possible programs with the
feature. I just feel (maybe feeling is not enough, but
opinions are also made of these unfortunately) that if a
new feature has to be introduced it should at least try to
play ball with the rest of the language. The more it does,
the more it can be used in any weird case that may come
up. One of the most beautiful things about C++ is that
there's pretty much always a way to do something, exactly
because the language is flexible and its parts can be
combined in many possible ways. A feature that creates a
non-extendable object is like a dead-end.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
I must agree with your last sentence, but I don't think the
strong-types I'm suggesting are non-extendable?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">What I mean=
is that
these wrappers should be part of the proposal and show
how the your copy class reach to make concrete and real
opaque types as e.g the energy example in P0109.<span class=
=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"></span><br>
<span class=3D"gmail-m_-1377447551499369339m_-4564586323290=
602189gmail-im"></span></blockquote>
<br>
</div>
<div>But wrappers can be made in a separate library. Why
should they be included in the proposal? As long as the
proposal allows them, a library only needs to be made once
(and if not needed by someone, not used).<br>
</div>
</div>
</div>
</div>
</blockquote></span>
We need some probe of concept applied to concrete examples we want
to solve. I believe a strong type feature must solve the builtin
type case. If your proposal is not a strong type proposal, then
forget my comments.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>You see that in order to have a custom type,
still many things must be written. So what's th=
e
difference between creating copyable wrappers
(using normal C++ rules), and creating a number
of such interfaces (having to learn and teach
how protected/public/private work in a new
context)? I don't see what the difference would
be. Why do you feel that wrappers on primitive
types are not enough?<br>
</div>
</div>
</blockquote>
</span> Yes, the new opaque type must define all the
available functions. Note that p0109 provides
conversions and the possibility to request the compiler
to generate the default trampolines. This is much sorter
than defining them using the current C++ language.
Implicit conversions (public) allow to use the new
opaque type where the underlying type was expected. <br>
<br>
I would prefer the opaque type proposal to go even
further (or an independent proposal) and be able to
introduce groups of trampolines as I did on my Opaque
library with the combined mixins. However I have no
concrete proposal at the language level. <br>
</blockquote>
<div><br>
</div>
<div>But I have made you an example with wrappers, which
you also agreed is similar to what your library
currently does. So what is wrong with that approach? <br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe we are not understanding one each other. My two last
paragraphs don't concern your proposal. It concerns p0109.<span><br=
>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>struct A {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
struct B : using A {};<br>
<br>
What will be the type of x<br>
<br>
B b1, b2;<br>
auto x =3D b1.append(b2);<br>
<br>
IIUC your proposal, the append function will be copied
replacing any occurrence of A by B, so it is as if B
was declared<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
Am I missing something? (***)<br>
<br>
Or would B equivalent to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(B const&);<br>
};<br>
<br>
or to<br>
<br>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 A append(A const&);<br>
};<br>
<br>
I'm wondering now if the copied class could add at al=
l
new non-static data members. Otherwise I don't see ho=
w
the duplication of such function can be done. I
suspect that p0109 doesn't allow to add new data.<br>
Then, if the user wants to add more data, it should
first duplicate the class and then inherit from the
duplicated class to add more data.<span class=3D"gmail-m_=
-1377447551499369339m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<br>
</div>
<div>No, you understood correctly, the end result would be
<br>
<br>
</div>
<div>
<div>struct B {<br>
</div>
=C2=A0 =C2=A0 B append(B const&);<br>
};<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Great.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Forcing the user to inherit to add more data adds
inheritance, which means that types are now implicitly
convertible (to at least a common base). I don't think
this is desirable. I think strong typing should work on
its own.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
How then you will be able to construct a B from a A if B adds more
non-static data members?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span cla=
ss=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>In some sense creating a new foo overload
using the type-copy. However, I believe this
would be a pretty big change. </div>
</div>
</div>
</blockquote>
</span> I believed this was already part of your
proposal. (***)<span class=3D"gmail-m_-137744755149936933=
9m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Mhh, now that you put it this way. I thought about
only doing this for classes. </div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Do you mean for member functions?<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>While the mechanism for free functions would be the
same (that's what I mean by strong-typedef of a
function, see below), the scope would be wider. One
only works for classes, the other on all free
functions. I don't know, maybe dividing them makes no
sense. I'd love to hear what you think about this.<br=
>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
As you want to inherit all the member functions from the underlying
class, it has a sens to concentrate on member functions. I don't
understand why friend functions could not follow the same schema.<span>=
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span c=
lass=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>As this is outside of the scope of my
proposal, I did not include this. And so,
I cannot add to my proposal the conversion
of friend and non-member function when
creating a copy-type. If this could be
included, there would be no problem for
that.<br>
</div>
</div>
</div>
</blockquote>
</span> Sorry, I don't know yet what are
type-aliases of methods. <br>
</blockquote>
<div><br>
</div>
<div>I'll try to explain myself better. A strong
typedef of a function would be taking that function
and replacing one or more types within it to others.
You could say that when you do:<br>
<br>
</div>
<div>template <typename T><br>
</div>
<div>void foo(T);<br>
<br>
</div>
<div>then foo<int> and foo<double> are
"strong typedefs" of each other, in some sens=
e. If
one were allowed to do this to existing code, one
could do something like<br>
<br>
</div>
<div>void foo(int);<br>
<br>
</div>
<div>void foo(double) : using foo(int);<br>
<br>
</div>
<div>to use an analogous syntax to the one in my
proposal. Not sure if this is clearer, let me know.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
I believe I understand you now but I don't see how this could help.=
<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0=
px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span=
class=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>For example, consider<br>
<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D de=
fault;<br>
</div>
<div>};<br>
</div>
<div>struct C : using B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator B() =3D de=
fault;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() =3D de=
fault;<br>
};<br>
<br>
</div>
<div>Just an idea.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I'm lost.<span class=3D"gmail-m_-13774475=
51499369339m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>What I mean is, if B is a strong typedef of A,
then we can default its conversion operator to A,
right? </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Right.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>But then, if C is a type-copy of B, then we can
default its conversion operator to both B (since
it's its type-copy), </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Right<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>and also to A (since C is a type-copy of a
type-copy).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
The first Opaque proposal contained a implicit subsumption relation
that allowed that. I'm all for, but I believe the committee doesn&#=
39;t
like transitivity in conversions.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><sp=
an class=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Is it really wise to allow the
compiler to be able to default
convert B to A? </div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I would say, yes. The question p0109
raise is whether the user wants it.<span class=3D"g=
mail-m_-1377447551499369339m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I'm not sure, however to me there's no
difference either way.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
The compiler is always able to do the conversion and the user
defines when the compiler will do it.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0=
px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><=
span class=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Maybe. I thought that
inherited classes are also
declared without mentioning that
they inherit, so I though that
the same should hold for copies.<br=
>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Maybe, but the C++ standard doesn't
have constrains on whether the class is
derived from another class.<span class=3D"gmail-m=
_-1377447551499369339m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>True. I'll try to think about this a bit
more. Maybe we could simply lift the
restriction and let the user do what he/she
wants? (so also use classes that are not
necessarily copies of the originals, as long
as their interface is compatible to what it
needs to be) <span class=3D"gmail-m_-137744755149=
9369339m_-4564586323290602189gmail-im"><br>
</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Maybe.<span><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
><span class=3D"gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"=
>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>That's true, and that=
9;s
mostly what I don't like
about giving the ability to
modify copied existing
methods. It is definitely
non-obvious that this is
happening. If you make a
mistake, it will take a long
time to figure out that you
involuntarily modified the
behavior of the original
class. That's bad in my
book.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> Maybe you need something like
override to state clearly that you want to
redefine the inherited behavior.<span class=3D"=
gmail-m_-1377447551499369339m_-4564586323290602189gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Unfortunately there would be nothing to
override, as you are adding a new overload
completely separate to the old one. Both
would still be usable and work, nothing is
being redefined. Simply the old function
would get linked against the new
implementation. There's nothing that the
compiler could do to prevent this.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Well, this is your proposal, and if you don't want to be able to
modify the duplicate class, you are then right. But if you where
able to modify the duplicated class, overriden could have a sense,
to mean replace it.<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>Best,<br>
</div>
<div>Eugenio<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Vicente<br>
</div><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9adc5a02-3209-bf63-a684-fb0272da56e0%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/std-proposals<wbr>/9adc=
5a02-3209-bf63-a684-<wbr>fb0272da56e0%40wanadoo.fr</a>.<br>
</blockquote></div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvZEjYakroOWxB8u%2BSCS%3D5u=
DGU5mdYpWpyCbD-qS-P3TQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%=
2BvZEjYakroOWxB8u%2BSCS%3D5uDGU5mdYpWpyCbD-qS-P3TQ%40mail.gmail.com</a>.<br=
/>
--001a113dc5885ce22c05451bbbab--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Mon, 2 Jan 2017 18:48:52 +0100
Raw View
This is a multi-part message in MIME format.
--------------95E436488BA40999444494AC
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 02/01/2017 =C3=A0 13:31, Eugenio Bargiacchi a =C3=A9crit :
> Dear Vicente,
>
> Eugenio, I believe the use cases we have both in mind are quite
> different, and so we don't reach to understand one to each other.
>
>
> It seems so. I am available to try other forms of communications if=20
> you want (chat, voice call) if you want. I'm sorry I'm not being as=20
> clear as I want.
No problem. It is my fault also.
>
> I have a question. Does you copy class proposal needs to have the
> definition of the copied class available?
> If yes, I don't think this could be acceptable.
> If the declaration is enough, the copied functions would need at
> least an internal conversion to/from the underlying type, isn't it?
>
>
> My proposal does not need the definition. Yes, I suppose an internal=20
> conversion would be needed. The internal conversion would probably=20
> work similarly to how inheritance works, even if adding non-static=20
> members was allowed. As in, the compiler knows that the first piece of=20
> the class will be the same as the original, and every new member is=20
> added at the end.
So if we argree that internal conversions are needed from/to the=20
underlying type, the new strong type couldn't add any new non-static=20
data member :)
>
>> B b;
>> b.A::bar(5);
>>
> Agreed. And the language let me do that even if you find it could
> be bad practice. I don't see why your copy approach wouldn't let
> me do that.
>
>
> In my approach the old function is impossible to hide, so I think that=20
> the two cases are different.
>
>> If in all these cases your answer is "the program will fail to
>> compile, just copy the class by hand" then I think the feature
>> would be severely limited in what it could actually do.
> You are probably right, and the copy should copy every thing and
> give access to everything internally. I need some concrete
> examples to understand what this possibility will solve.
>
>
> Well, for example, a library that wanted to create strong typedefs of=20
> primitive types via wrappers and only expose certain operations,=20
> without getters/setters ;) I've added some code later to show you how=20
> a possible implementation using this proposal.
>
>> If I understand correctly, you want to hide the original
>> completely, and just be offered an easy way to bring back some of
>> its interface (via trampolines) to its "wrapper", which would be
>> the strong typedef.
> I wouldn't say hiding, just don't looking inside the underlying
> type. I want to provide access to it (when needed) but only as a
> whole.
>> Possibly adding more public methods only using the public
>> interface, which could be done just the same with non-member
>> methods. The end result is a class that cannot be extended in any
>> meaningful way using any of the normal C++ facilities, since
>> every juicy bit is hidden.
> Why it is unusable? The class provide access to everything you want.
>
>
> Classes don't always come with getters and setters for every private=20
> field. Especially if the interface they provide is a high level one.=20
> It happens often in low-level code that you want to interact with the=20
> underlying bits in very specific ways, but you don't necessarily want=20
> to give that kind of access to users. So creating a strong typedef of=20
> such a class while adding a new mode of operation would be impossible,=20
> as the copy won't have access to the underlying implementation.
>
> Another could be when you have to types that you know contain the same=20
> (private) data, but should expose different public interfaces. Then=20
> you could first create the class containing the data, and copy it two=20
> times, each time exposing a different interface (which would need=20
> access to the private data). Once again, I unfortunately don't have a=20
> practical use case at the moment. I just think it could be useful.
>
> Still the code below is a good use-case I think, since it would be=20
> needed to provide strong typedefs of primitive types.
>
>> Applying strong-typing again to a strong-typed class would be
>> useless as access to internals would be the same,
> You can strong-type again. I don't see the trouble. E.g; you can
> have a energy strong-type and have kinetic_energy,
> potential_energy and heat_energy strong-type of energy.
> Typing and representation are two different things. Strong types
> are just that. Share a representation and have different types.
>
>
> Yes, of course. What I mean is, you have created a class which can=20
> only create exact copies of it. If you need additional changes, it=20
> will probably be easier to strong-type the original again and create=20
> new trampolines from that. This is what I mean by non-extendable.
Why? I don't understand.
>
>> aside from possibly adding more data (if needed) in the public
>> attributes, since only those are editable. This would also
>> prevent encapsulation of new data. If not, it would just mean
>> that the feature wouldn't be used in a composable way.
> I believe now that strong-type shouldn't add any new non-static
> data member
>
>
> I start to see what you mean. But still, if one could add them, the=20
> copy would still "contain" an equivalent of the original class at its=20
> beginning. It wouldn't be guaranteed reinterpret_cast-able, but the=20
> fields would be there anyway. The original representation is there -=20
> so to me it could still be considered a strong-typedef (stretching a=20
> bit the definition maybe).
Remember that you need conversions from both sides to implement the=20
trampolines.
>
> Is there any other reason why you don't like the idea?
No, but it is enough.
>
>> A feature that creates a non-extendable object is like a dead-end.
> I must agree with your last sentence, but I don't think the
> strong-types I'm suggesting are non-extendable?
>
>
> Well, if only the public interface is available, than adding new=20
> methods to it is pretty much equivalent with creating non-member=20
> functions (since those work with public interface). Then you might as=20
> well remove the ability to add new member functions, since non-members=20
> will do just fine and there's no need to have them as members.
People like member functions also ;-)
>
>> But wrappers can be made in a separate library. Why should they
>> be included in the proposal? As long as the proposal allows them,
>> a library only needs to be made once (and if not needed by
>> someone, not used).
> We need some probe of concept applied to concrete examples we want
> to solve. I believe a strong type feature must solve the builtin
> type case. If your proposal is not a strong type proposal, then
> forget my comments.
>
>
> This is how I would practically solve the primitive types problem=20
> using my proposal:
>
> ------------------------------------------
>
> // library.hpp
>
> template <typename T>
> class Wrap {
> public:
> using base_type =3D T;
>
> Wrap(const Wrap & other) : t_(other.t_) {}
> explicit Wrap(T t) : t_(t) {}
>
> private:
> T t_;
> };
>
> template <typename C>
> class ConvertBack : using C {
public:
> operator base_type() { return t_; }
> };
>
> template <typename C>
> class Plus : using C {
public:
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> };
>
> template <typename C>
> class Minus : using C {
> Minus operator-(Minus other) { return Minus{t_ - other.t_}; }
> };
>
> template <typename C>
> class Prod : using C {
> Prod operator+(Prod other) { return Prod{t_ * other.t_}; }
> };
>
> template <typename C>
> class Div : using C {
> Div operator/(Div other) { return Div{t_ / other.t_}; }
> };
>
> template <typename T>
> using Arithmetic =3D Div<Prod<Minus<Plus<Wrap<T>>>>>;
>
> // .... and so on
>
> // usercode.cpp
>
> #include "library.hpp"
>
> // Strong typedef of int with +,-,/,*
> struct MyInt : using Arithmetic<int> {}
>
> // Strong typedef of double with +,- convertible to double
> struct MyDouble : using ConvertBack<Minus<Plus<Wrap<double>>>> {}
>
This example is already more complete. Thanks.
> --------------------------------------------
ConvertBack will convert to Minus<Plus<Wrap<double>>> :(
Maybe the conversion should be part of Wrap or wrap should provide a=20
underlying function as I have in my library.
operator+ returns Plus<Wrap<double>> but we want MyInt or MyDouble :(
See below how you could return the Final class.
>
> If there's something missing you'd like to see how I'd do, let me=20
> know. Of course verbosity depends on granularity. If all operations=20
> need to be manually selected you'll have lots of classes. If the=20
> granularity required is less each class could add more operators at once.
>
> Note that you need access to privates to be able to do this, so this=20
> could be an use-case for that.
I like the idea and yes it needs access to the private data. However if=20
we want to be able to provide the conversion to the underlying type, it=20
seems that the underlying data is no more private anymore and should at=20
least be read. To be fair, I have never created strong types for classes=20
that are not builtin types, or that are not copied completely. If the=20
function you want to add modifies only part of the underlying type then=20
either the underlying type provides already this possibility, or the new=20
type would need access to the private part as you propose.
I would need to see how I could adapt my Opaque library with this=20
language feature and see if it could be more simple. I will try with=20
private and without access.
>
> A problem that is not tackled in this code and that we are also=20
> discussing is what to do with non-member functions (that could=20
> possibly take base_type as input). That depends on how non-member=20
> functions will be handled in the proposals. If they can be handled I=20
> would actually be happier.
template <typename Final, typename C>
class AFct : using C {
public:
friend Final aFct(Final other) { return Final{aFct(other.t_)}; }
};
>
>> Forcing the user to inherit to add more data adds inheritance,
>> which means that types are now implicitly convertible (to at
>> least a common base). I don't think this is desirable. I think
>> strong typing should work on its own.
> How then you will be able to construct a B from a A if B adds more
> non-static data members?
>
>
> One option is to simply define a constructor in B which takes A.=20
> Otherwise, it would be the same case when you create a class with a=20
> member which the constructor does not initialize. Otherwise one=20
> exception could be made for constructors so that they can be redefined=20
> in the new class. This probably makes sense and it shoudn't be=20
> possible to break something (unless one creates a constructor which=20
> does not initialize some fields which are assumed initialized by the=20
> original class.. but then I believe it's a reasonable risk).
I suggest you try it and see how it works. Let me know if it is reasonable.
>
> As you want to inherit all the member functions from the
> underlying class, it has a sens to concentrate on member
> functions. I don't understand why friend functions could not
> follow the same schema.
>
>
> Well, friend functions are not members, so if you allow copying them,=20
> you are allowing copying arbitrary non-member functions (which I=20
> approve of). The only problem with this is that it is a big change -=20
> on top of this proposal. Just that.
Not exactly. The compiler can copy the friend functions because it is=20
aware of these functions and so it could copy them.
>
>> void foo(int);
>>
>> void foo(double) : using foo(int);
>>
>> to use an analogous syntax to the one in my proposal. Not sure if
>> this is clearer, let me know.
> I believe I understand you now but I don't see how this could help.
>
> Well, this would be the way to create the "trampolines" for non-member=20
> functions. When you copy a class, you specify just once from which=20
> class you are copying. The compiler can then apply the change to all=20
> member functions automatically.
>
> However, you still have to specify non-member functions manually,=20
> since the compiler cannot assume you want them all.
I believe you could let the user copy non-member non-friend function by=20
itself.
>
>> and also to A (since C is a type-copy of a type-copy).
> The first Opaque proposal contained a implicit subsumption
> relation that allowed that. I'm all for, but I believe the
> committee doesn't like transitivity in conversions.
>
>
> Well, it is not really transitivity. As in, the C to A transition does=20
> not need an implicit transition from B. The user is explicitly=20
> creating the conversion operator. The data in C exists, so it can be=20
> copied directly. Maybe you mean transitivity in the sense that the=20
> compiler needs to remember that C is a copy of B in order for it to=20
> know that it is also a copy of A. In that case I agree.
Yes this is the case. You are requesting the compiler to do the=20
conversion transitively.
Vicente
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/edb42928-1e58-ee22-79ce-0fedd07247f1%40wanadoo.f=
r.
--------------95E436488BA40999444494AC
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 02/01/2017 =C3=A0 13:31, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">Dear Vicente,<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Eu=
genio,
I believe the use cases we have both in mind are quite
different, and so we don't reach to understand one to each
other.</blockquote>
<div><br>
</div>
<div>It seems so. I am available to try other forms of
communications if you want (chat, voice call) if you want. I'm
sorry I'm not being as clear as I want.<br>
</div>
</div>
</blockquote>
No problem. It is my fault also.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">I have a question. Does
you copy class proposal needs to have the definition of the
copied class available?<br>
If yes, I don't think this could be acceptable.<br>
If the declaration is enough, the copied functions would
need at least an internal conversion to/from the underlying
type, isn't it?<span
class=3D"gmail-m_-1377447551499369339gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>My proposal does not need the definition. Yes, I suppose
an internal conversion would be needed. The internal
conversion would probably work similarly to how inheritance
works, even if adding non-static members was allowed. As in,
the compiler knows that the first piece of the class will be
the same as the original, and every new member is added at
the end.<span class=3D"gmail-m_-1377447551499369339gmail-im"><b=
r>
</span></div>
</div>
</div>
</blockquote>
So if we argree that internal conversions are needed from/to the
underlying type, the new strong type couldn't add any new non-static
data member :)<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-m_-1377447551499369339gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>B b;<br>
b.A::bar(5);<br>
<br>
</div>
</div>
</div>
</blockquote>
</span> Agreed. And the language let me do that even if
you find it could be bad practice. I don't see why your
copy approach wouldn't let me do that.<span
class=3D"gmail-m_-1377447551499369339gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>In my approach the old function is impossible to hide,
so I think that the two cases are different.<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>If in all these cases your answer is "the
program will fail to compile, just copy the
class by hand" then I think the feature
would be severely limited in what it could
actually do.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are probably right, and the copy should copy
every thing and give access to everything internally. I
need some concrete examples to understand what this
possibility will solve.<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Well, for example, a library that wanted to create
strong typedefs of primitive types via wrappers and only
expose certain operations, without getters/setters ;)
I've added some code later to show you how a possible
implementation using this proposal.<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> If I understand correctly, you want to
hide the original completely, and just be
offered an easy way to bring back some of
its interface (via trampolines) to its
"wrapper", which would be the strong
typedef. </div>
</div>
</div>
</div>
</blockquote>
</span> I wouldn't say hiding, just don't looking
inside the underlying type. I want to provide access
to it (when needed) but only as a whole.<span
class=3D"gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Possibly adding more public methods
only using the public interface, which
could be done just the same with
non-member methods. The end result is a
class that cannot be extended in any
meaningful way using any of the normal C++
facilities, since every juicy bit is
hidden. </div>
</div>
</div>
</div>
</blockquote>
</span> Why it is unusable? The class provide access
to everything you want.<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Classes don't always come with getters and setters
for every private field. Especially if the interface
they provide is a high level one. It happens often in
low-level code that you want to interact with the
underlying bits in very specific ways, but you don't
necessarily want to give that kind of access to users.
So creating a strong typedef of such a class while
adding a new mode of operation would be impossible, as
the copy won't have access to the underlying
implementation.<br>
<br>
Another could be when you have to types that you know
contain the same (private) data, but should expose
different public interfaces. Then you could first
create the class containing the data, and copy it two
times, each time exposing a different interface (which
would need access to the private data). Once again, I
unfortunately don't have a practical use case at the
moment. I just think it could be useful.<br>
<br>
</div>
<div>Still the code below is a good use-case I think,
since it would be needed to provide strong typedefs of
primitive types.<br>
</div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px
0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying strong-typing again to a
strong-typed class would be useless as
access to internals would be the same, </di=
v>
</div>
</div>
</div>
</blockquote>
</span> You can strong-type again. I don't see the
trouble. E.g; you can have a energy strong-type and
have kinetic_energy, potential_energy and=C2=A0
heat_energy strong-type of energy.<br>
Typing and representation are two different things.
Strong types are just that. Share a representation
and have different types.<span class=3D"gmail-im"><br>
</span></blockquote>
</div>
</div>
</div>
<br>
</div>
<div>Yes, of course. What I mean is, you have created a class
which can only create exact copies of it. If you need
additional changes, it will probably be easier to
strong-type the original again and create new trampolines
from that. This is what I mean by non-extendable.<br>
</div>
</div>
</div>
</blockquote>
Why? I don't understand.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>aside from possibly adding more data (if
needed) in the public attributes, since only
those are editable. This would also prevent
encapsulation of new data. If not, it would
just mean that the feature wouldn't be used in
a composable way.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe now that strong-type shouldn't add any
new non-static data member</blockquote>
<div><br>
</div>
<div>I start to see what you mean. But still, if one could
add them, the copy would still "contain" an equivalent of
the original class at its beginning. It wouldn't be
guaranteed reinterpret_cast-able, but the fields would be
there anyway. The original representation is there - so to
me it could still be considered a strong-typedef
(stretching a bit the definition maybe).<br>
</div>
</div>
</div>
</div>
</blockquote>
Remember that you need conversions from both sides to implement the
trampolines.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>Is there any other reason why you don't like the idea?<br>
</div>
</div>
</div>
</div>
</blockquote>
No, but it is enough. <br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>A feature that creates a non-extendable
object is like a dead-end.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I must agree with your last sentence, but I
don't think the strong-types I'm suggesting are
non-extendable?<span class=3D"gmail-im"></span> <br>
</blockquote>
</div>
<div><br>
</div>
<div>Well, if only the public interface is available, than
adding new methods to it is pretty much equivalent with
creating non-member functions (since those work with
public interface). Then you might as well remove the
ability to add new member functions, since non-members
will do just fine and there's no need to have them as
members.<br>
</div>
</div>
</div>
</div>
</blockquote>
People like member functions also ;-)<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>But wrappers can be made in a separate
library. Why should they be included in the
proposal? As long as the proposal allows
them, a library only needs to be made once
(and if not needed by someone, not used).<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> We need some probe of concept applied to
concrete examples we want to solve. I believe a strong
type feature must solve the builtin type case. If your
proposal is not a strong type proposal, then forget my
comments.<span class=3D"gmail-im"><br>
</span></blockquote>
</div>
<div><span class=3D"gmail-im"></span><br>
</div>
<div>This is how I would practically solve the primitive
types problem using my proposal:<br>
<br>
------------------------------------------<br>
<br>
// library.hpp<br>
<br>
template <typename T><br>
class Wrap {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 using base_type =
=3D T;<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Wrap(const Wrap &a=
mp; other) : t_(other.t_) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 explicit Wrap(T t)=
: t_(t) {}<br>
=C2=A0=C2=A0=C2=A0 <br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br>
};<br>
<br>
template <typename C><br>
class ConvertBack : using C {<br>
</div>
</div>
</div>
</div>
</blockquote>
public:<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>=C2=A0=C2=A0=C2=A0 operator base_type() { return t_; }<br>
};<br>
<br>
template <typename C><br>
class Plus : using C {<br>
</div>
</div>
</div>
</div>
</blockquote>
public:<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plu=
s{t_ +
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Minus : using C {<br>
=C2=A0=C2=A0=C2=A0 Minus operator-(Minus other) { return Minu=
s{t_ -
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Prod : using C {<br>
=C2=A0=C2=A0=C2=A0 Prod operator+(Prod other) { return Prod{t=
_ *
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Div : using C {<br>
=C2=A0=C2=A0=C2=A0 Div operator/(Div other) { return Div{t_ /=
other.t_};
}<br>
};<br>
<br>
template <typename T><br>
using Arithmetic =3D
Div<Prod<Minus<Plus<Wrap<T>>>>>=
;<br>
<br>
// .... and so on<br>
<br>
// usercode.cpp<br>
<br>
#include "library.hpp"<br>
<br>
// Strong typedef of int with +,-,/,*<br>
struct MyInt : using Arithmetic<int> {}<br>
<br>
// Strong typedef of double with +,- convertible to double<br=
>
struct MyDouble : using
ConvertBack<Minus<Plus<Wrap<double>>>>=
;
{}<br>
<br>
</div>
</div>
</div>
</div>
</blockquote>
This example is already more complete. Thanks.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>--------------------------------------------</div>
</div>
</div>
</div>
</blockquote>
ConvertBack will convert to
Minus<Plus<Wrap<double>>> :(<br>
<br>
Maybe the conversion should be part of Wrap or wrap should provide a
underlying function as I have in my library.<br>
<br>
operator+ returns Plus<Wrap<double>> but we want MyInt
or MyDouble :(<br>
<br>
See below how you could return the Final class. <br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">If there's something missing you'd like
to see how I'd do, let me know. Of course verbosity depends on
granularity. If all operations need to be manually selected
you'll have lots of classes. If the granularity required is
less each class could add more operators at once.<br>
<br>
</div>
<div class=3D"gmail_extra">Note that you need access to privates
to be able to do this, so this could be an use-case for that.<br>
</div>
</div>
</blockquote>
I like the idea and yes it needs access to the private data. However
if we want to be able to provide the conversion to the underlying
type, it seems that the underlying data=C2=A0 is no more private anymor=
e
and should at least be read. To be fair, I have never created strong
types for classes that are not builtin types, or that are not copied
completely. If the function you want to add modifies only part of
the underlying type then either the underlying type provides already
this possibility, or the new type would need access to the private
part as you propose.<br>
<br>
I would need to see how I could adapt my Opaque library with this
language feature and see if it could be more simple. I will try with
private and without access.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">A problem that is not tackled in this
code and that we are also discussing is what to do with
non-member functions (that could possibly take base_type as
input). That depends on how non-member functions will be
handled in the proposals. If they can be handled I would
actually be happier.<br>
</div>
</div>
</blockquote>
template <typename Final, typename C><br>
class AFct : using C {<br>
public:<br>
=C2=A0=C2=A0=C2=A0 friend Final aFct(Final other) { return Final{aFct(o=
ther.t_)}; }<br>
};
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Forcing the user to inherit to add more
data adds inheritance, which means that types
are now implicitly convertible (to at least a
common base). I don't think this is desirable.
I think strong typing should work on its own.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> How then you will be able to construct a B from a A
if B adds more non-static data members?<span
class=3D"gmail-im"><br>
</span></blockquote>
</div>
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">One option is to simply define a
constructor in B which takes A. Otherwise, it would be the
same case when you create a class with a member which the
constructor does not initialize. Otherwise one exception could
be made for constructors so that they can be redefined in the
new class. This probably makes sense and it shoudn't be
possible to break something (unless one creates a constructor
which does not initialize some fields which are assumed
initialized by the original class.. but then I believe it's a
reasonable risk).<br>
</div>
</div>
</blockquote>
I suggest you try it and see how it works. Let me know if it is
reasonable.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">As you want to inherit
all the member functions from the underlying class, it has a
sens to concentrate on member functions. I don't understand
why friend functions could not follow the same schema.<span
class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Well, friend functions are not members, so if you allow
copying them, you are allowing copying arbitrary non-member
functions (which I approve of). The only problem with this
is that it is a big change - on top of this proposal. Just
that.<br>
</div>
</div>
</div>
</blockquote>
Not exactly. The compiler can copy the friend functions because it
is aware of these functions and so it could copy them.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra">
<div><span class=3D"gmail-im"><br>
</span><span class=3D"gmail-im"></span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>void foo(int);<br>
<br>
</div>
<div>void foo(double) : using foo(int);<br>
<br>
</div>
<div>to use an analogous syntax to the one
in my proposal. Not sure if this is
clearer, let me know.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe I understand you now but I don't see how
this could help.<span class=3D"gmail-im"><br>
</span></blockquote>
=C2=A0</div>
</div>
<div class=3D"gmail_extra">Well, this would be the way to create
the "trampolines" for non-member functions. When you copy a
class, you specify just once from which class you are copying.
The compiler can then apply the change to all member functions
automatically.<br>
<br>
However, you still have to specify non-member functions
manually, since the compiler cannot assume you want them all.<br>
</div>
</div>
</blockquote>
I believe you could let the user copy non-member non-friend function
by itself.<br>
<blockquote
cite=3D"mid:CAHfn=3D+vZEjYakroOWxB8u+SCS=3D5uDGU5mdYpWpyCbD-qS-P3TQ@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><span class=3D"gmail-im"><br>
</span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>and also to A (since C is a type-copy
of a type-copy).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> The first Opaque proposal contained a implicit
subsumption relation that allowed that. I'm all for, but I
believe the committee doesn't like transitivity in
conversions.<span class=3D"gmail-im"><br>
</span></blockquote>
<br>
</div>
<div class=3D"gmail_extra">Well, it is not really transitivity. As
in, the C to A transition does not need an implicit transition
from B. The user is explicitly creating the conversion
operator. The data in C exists, so it can be copied directly.
Maybe you mean transitivity in the sense that the compiler
needs to remember that C is a copy of B in order for it to
know that it is also a copy of A. In that case I agree.<br>
</div>
</div>
</blockquote>
Yes this is the case. You are requesting the compiler to do the
conversion transitively.<br>
<br>
<br>
Vicente
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/edb42928-1e58-ee22-79ce-0fedd07247f1%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/edb42928-1e58-ee22-79ce-0fedd07247f1=
%40wanadoo.fr</a>.<br />
--------------95E436488BA40999444494AC--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Mon, 2 Jan 2017 19:21:53 +0100
Raw View
--f403045dd9604a4623054520a069
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vicente,
> As in, the compiler knows that the first piece of the class will be the
> same as the original, and every new member is added at the end.
>
> So if we argree that internal conversions are needed from/to the
> underlying type, the new strong type couldn't add any new non-static data
> member :)
>
I'm not sure I agree fully, but in any case the ability to add new
non-static data members is not something I feel strongly about at the
moment. It's something that can be added in a future proposal if there
should arise a need. =3D)
Maybe I'll just remove this from the proposal for the moment.
> Yes, of course. What I mean is, you have created a class which can only
> create exact copies of it. If you need additional changes, it will probab=
ly
> be easier to strong-type the original again and create new trampolines fr=
om
> that. This is what I mean by non-extendable.
>
> Why? I don't understand.
>
It may be that I just have a different idea in my head on how p0109 would
work in practice. I just have a feeling that those strong typedefs could be
hard to work with, but I may just have misunderstood some parts.
> I start to see what you mean. But still, if one could add them, the copy
> would still "contain" an equivalent of the original class at its beginnin=
g.
> It wouldn't be guaranteed reinterpret_cast-able, but the fields would be
> there anyway. The original representation is there - so to me it could
> still be considered a strong-typedef (stretching a bit the definition
> maybe).
>
> Remember that you need conversions from both sides to implement the
> trampolines.
>
Well, in inheritance child classes can be converted to their parents
automatically (even if they don't define a constructor that initializes any
new data they might have). If that can be done I don't see why this would
be impossible for a copied class + a new non-static data member to do the
same thing.
> Well, if only the public interface is available, than adding new methods
> to it is pretty much equivalent with creating non-member functions (since
> those work with public interface). Then you might as well remove the
> ability to add new member functions, since non-members will do just fine
> and there's no need to have them as members.
>
> People like member functions also ;-)
>
Eh, true. But every feature must be justified by a use case! ;D (joking)
> template <typename C>
> class ConvertBack : using C {
>
> public:
>
Whoops!
> // Strong typedef of double with +,- convertible to double
> struct MyDouble : using ConvertBack<Minus<Plus<Wrap<double>>>> {}
>
> This example is already more complete. Thanks.
>
> --------------------------------------------
>
> ConvertBack will convert to Minus<Plus<Wrap<double>>> :(
>
> Maybe the conversion should be part of Wrap or wrap should provide a
> underlying function as I have in my library.
>
> operator+ returns Plus<Wrap<double>> but we want MyInt or MyDouble :(
>
> See below how you could return the Final class.
>
Not exactly!
I'll try to analyze MyDouble to explain how it works.
Wrap<double> I believe we both understand it. So now let's consider
Plus<Wrap<double>>.
template <typename C>
struct Plus : using C { // changed to struct to avoid public
Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
};
So it copies the templated class, and adds the operator+ to it. So the
class becomes the equivalent of:
struct Plus { // Equivalent of Plus<Wrap<double>>
using base_type =3D double;
Plus(const Plus & other) : t_(other.t_) {}
explicit Plus(double t) : t_(t) {}
Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
private:
double t_;
};
See? Now any mention of Wrap has disappeared, since we copied that.
Wrap<double>, the original class, has been replaced by Plus (since we are
copying). After the minus, the same thing would happen:
struct Minus { // Equivalent of struct Minus<Plus<Wrap<double>>>
using base_type =3D double;
Minus(const Minus & other) : t_(other.t_) {}
explicit Minus(double t) : t_(t) {}
Minus operator+(Minus other) { return Minus{t_ + other.t_}; }
Minus operator-(Minus other) { return Minus{t_ - other.t_}; }
private:
double t_;
};
And finally, the last step:
struct ConvertBack { // Equivalent of struct
ConvertBack<Minus<Plus<Wrap<double>>>>
using base_type =3D double;
ConvertBack(const ConvertBack & other) : t_(other.t_) {}
explicit ConvertBack(double t) : t_(t) {}
// From Plus originally
ConvertBack operator+(ConvertBack other) { return ConvertBack{t_ +
other.t_}; }
// From Minus originally
ConvertBack operator-(ConvertBack other) { return ConvertBack{t_ -
other.t_}; }
// From ConvertBack, unchanged, but using the typedef (base_type) made
initially in Wrap<double>
operator base_type() { return t_; }
private:
double t_;
};
I hope this makes more sense to you.
template <typename Final, typename C>
> class AFct : using C {
> public:
> friend Final aFct(Final other) { return Final{aFct(other.t_)}; }
> };
This could be a way, yes.
One option is to simply define a constructor in B which takes A. Otherwise,
> it would be the same case when you create a class with a member which the
> constructor does not initialize. Otherwise one exception could be made fo=
r
> constructors so that they can be redefined in the new class. This probabl=
y
> makes sense and it shoudn't be possible to break something (unless one
> creates a constructor which does not initialize some fields which are
> assumed initialized by the original class.. but then I believe it's a
> reasonable risk).
>
> I suggest you try it and see how it works. Let me know if it is reasonabl=
e.
>
I'll try to work on this a bit then.
Well, friend functions are not members, so if you allow copying them, you
> are allowing copying arbitrary non-member functions (which I approve of).
> The only problem with this is that it is a big change - on top of this
> proposal. Just that.
>
> Not exactly. The compiler can copy the friend functions because it is
> aware of these functions and so it could copy them.
>
This seems reasonable.
However, you still have to specify non-member functions manually, since the
> compiler cannot assume you want them all.
>
> I believe you could let the user copy non-member non-friend function by
> itself.
Yes. However, can you do this process on random non-member functions to
change their parameters to other types? If not, why not? Are you
constrained in doing this only in copied class and with functions
taking/returning the original class, maybe? Why?
I'm not sure what the answers should be.
Well, it is not really transitivity. As in, the C to A transition does not
> need an implicit transition from B. The user is explicitly creating the
> conversion operator. The data in C exists, so it can be copied directly.
> Maybe you mean transitivity in the sense that the compiler needs to
> remember that C is a copy of B in order for it to know that it is also a
> copy of A. In that case I agree.
>
> Yes this is the case. You are requesting the compiler to do the conversio=
n
> transitively.
>
Makes sense. Then forget the idea =3D)
Best,
Eugenio
On Mon, Jan 2, 2017 at 6:48 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 02/01/2017 =C3=A0 13:31, Eugenio Bargiacchi a =C3=A9crit :
>
> Dear Vicente,
>
> Eugenio, I believe the use cases we have both in mind are quite different=
,
>> and so we don't reach to understand one to each other.
>
>
> It seems so. I am available to try other forms of communications if you
> want (chat, voice call) if you want. I'm sorry I'm not being as clear as =
I
> want.
>
> No problem. It is my fault also.
>
>
> I have a question. Does you copy class proposal needs to have the
>> definition of the copied class available?
>> If yes, I don't think this could be acceptable.
>> If the declaration is enough, the copied functions would need at least a=
n
>> internal conversion to/from the underlying type, isn't it?
>>
>
> My proposal does not need the definition. Yes, I suppose an internal
> conversion would be needed. The internal conversion would probably work
> similarly to how inheritance works, even if adding non-static members was
> allowed. As in, the compiler knows that the first piece of the class will
> be the same as the original, and every new member is added at the end.
>
> So if we argree that internal conversions are needed from/to the
> underlying type, the new strong type couldn't add any new non-static data
> member :)
>
> B b;
>> b.A::bar(5);
>>
>> Agreed. And the language let me do that even if you find it could be bad
>> practice. I don't see why your copy approach wouldn't let me do that.
>>
>
> In my approach the old function is impossible to hide, so I think that th=
e
> two cases are different.
>
>> If in all these cases your answer is "the program will fail to compile,
>> just copy the class by hand" then I think the feature would be severely
>> limited in what it could actually do.
>>
>> You are probably right, and the copy should copy every thing and give
>> access to everything internally. I need some concrete examples to
>> understand what this possibility will solve.
>>
>
> Well, for example, a library that wanted to create strong typedefs of
> primitive types via wrappers and only expose certain operations, without
> getters/setters ;) I've added some code later to show you how a possible
> implementation using this proposal.
>
>> If I understand correctly, you want to hide the original completely, and
>> just be offered an easy way to bring back some of its interface (via
>> trampolines) to its "wrapper", which would be the strong typedef.
>>
>> I wouldn't say hiding, just don't looking inside the underlying type. I
>> want to provide access to it (when needed) but only as a whole.
>>
>> Possibly adding more public methods only using the public interface,
>> which could be done just the same with non-member methods. The end resul=
t
>> is a class that cannot be extended in any meaningful way using any of th=
e
>> normal C++ facilities, since every juicy bit is hidden.
>>
>> Why it is unusable? The class provide access to everything you want.
>>
>
> Classes don't always come with getters and setters for every private
> field. Especially if the interface they provide is a high level one. It
> happens often in low-level code that you want to interact with the
> underlying bits in very specific ways, but you don't necessarily want to
> give that kind of access to users. So creating a strong typedef of such a
> class while adding a new mode of operation would be impossible, as the co=
py
> won't have access to the underlying implementation.
>
> Another could be when you have to types that you know contain the same
> (private) data, but should expose different public interfaces. Then you
> could first create the class containing the data, and copy it two times,
> each time exposing a different interface (which would need access to the
> private data). Once again, I unfortunately don't have a practical use cas=
e
> at the moment. I just think it could be useful.
>
> Still the code below is a good use-case I think, since it would be needed
> to provide strong typedefs of primitive types.
>
>> Applying strong-typing again to a strong-typed class would be useless as
>> access to internals would be the same,
>>
>> You can strong-type again. I don't see the trouble. E.g; you can have a
>> energy strong-type and have kinetic_energy, potential_energy and
>> heat_energy strong-type of energy.
>> Typing and representation are two different things. Strong types are jus=
t
>> that. Share a representation and have different types.
>>
>
> Yes, of course. What I mean is, you have created a class which can only
> create exact copies of it. If you need additional changes, it will probab=
ly
> be easier to strong-type the original again and create new trampolines fr=
om
> that. This is what I mean by non-extendable.
>
> Why? I don't understand.
>
> aside from possibly adding more data (if needed) in the public attributes=
,
>> since only those are editable. This would also prevent encapsulation of =
new
>> data. If not, it would just mean that the feature wouldn't be used in a
>> composable way.
>>
>> I believe now that strong-type shouldn't add any new non-static data
>> member
>
>
> I start to see what you mean. But still, if one could add them, the copy
> would still "contain" an equivalent of the original class at its beginnin=
g.
> It wouldn't be guaranteed reinterpret_cast-able, but the fields would be
> there anyway. The original representation is there - so to me it could
> still be considered a strong-typedef (stretching a bit the definition
> maybe).
>
> Remember that you need conversions from both sides to implement the
> trampolines.
>
>
> Is there any other reason why you don't like the idea?
>
> No, but it is enough.
>
> A feature that creates a non-extendable object is like a dead-end.
>>
>> I must agree with your last sentence, but I don't think the strong-types
>> I'm suggesting are non-extendable?
>>
>
> Well, if only the public interface is available, than adding new methods
> to it is pretty much equivalent with creating non-member functions (since
> those work with public interface). Then you might as well remove the
> ability to add new member functions, since non-members will do just fine
> and there's no need to have them as members.
>
> People like member functions also ;-)
>
>
> But wrappers can be made in a separate library. Why should they be
>> included in the proposal? As long as the proposal allows them, a library
>> only needs to be made once (and if not needed by someone, not used).
>>
>> We need some probe of concept applied to concrete examples we want to
>> solve. I believe a strong type feature must solve the builtin type case.=
If
>> your proposal is not a strong type proposal, then forget my comments.
>>
>
> This is how I would practically solve the primitive types problem using m=
y
> proposal:
>
> ------------------------------------------
>
> // library.hpp
>
> template <typename T>
> class Wrap {
> public:
> using base_type =3D T;
>
> Wrap(const Wrap & other) : t_(other.t_) {}
> explicit Wrap(T t) : t_(t) {}
>
> private:
> T t_;
> };
>
> template <typename C>
> class ConvertBack : using C {
>
> public:
>
> operator base_type() { return t_; }
> };
>
> template <typename C>
> class Plus : using C {
>
> public:
>
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> };
>
> template <typename C>
> class Minus : using C {
> Minus operator-(Minus other) { return Minus{t_ - other.t_}; }
> };
>
> template <typename C>
> class Prod : using C {
> Prod operator+(Prod other) { return Prod{t_ * other.t_}; }
> };
>
> template <typename C>
> class Div : using C {
> Div operator/(Div other) { return Div{t_ / other.t_}; }
> };
>
> template <typename T>
> using Arithmetic =3D Div<Prod<Minus<Plus<Wrap<T>>>>>;
>
> // .... and so on
>
> // usercode.cpp
>
> #include "library.hpp"
>
> // Strong typedef of int with +,-,/,*
> struct MyInt : using Arithmetic<int> {}
>
> // Strong typedef of double with +,- convertible to double
> struct MyDouble : using ConvertBack<Minus<Plus<Wrap<double>>>> {}
>
> This example is already more complete. Thanks.
>
> --------------------------------------------
>
> ConvertBack will convert to Minus<Plus<Wrap<double>>> :(
>
> Maybe the conversion should be part of Wrap or wrap should provide a
> underlying function as I have in my library.
>
> operator+ returns Plus<Wrap<double>> but we want MyInt or MyDouble :(
>
> See below how you could return the Final class.
>
>
> If there's something missing you'd like to see how I'd do, let me know. O=
f
> course verbosity depends on granularity. If all operations need to be
> manually selected you'll have lots of classes. If the granularity require=
d
> is less each class could add more operators at once.
>
> Note that you need access to privates to be able to do this, so this coul=
d
> be an use-case for that.
>
> I like the idea and yes it needs access to the private data. However if w=
e
> want to be able to provide the conversion to the underlying type, it seem=
s
> that the underlying data is no more private anymore and should at least =
be
> read. To be fair, I have never created strong types for classes that are
> not builtin types, or that are not copied completely. If the function you
> want to add modifies only part of the underlying type then either the
> underlying type provides already this possibility, or the new type would
> need access to the private part as you propose.
>
> I would need to see how I could adapt my Opaque library with this languag=
e
> feature and see if it could be more simple. I will try with private and
> without access.
>
>
> A problem that is not tackled in this code and that we are also discussin=
g
> is what to do with non-member functions (that could possibly take base_ty=
pe
> as input). That depends on how non-member functions will be handled in th=
e
> proposals. If they can be handled I would actually be happier.
>
> template <typename Final, typename C>
> class AFct : using C {
> public:
> friend Final aFct(Final other) { return Final{aFct(other.t_)}; }
> };
>
>
> Forcing the user to inherit to add more data adds inheritance, which mean=
s
>> that types are now implicitly convertible (to at least a common base). I
>> don't think this is desirable. I think strong typing should work on its =
own.
>>
>> How then you will be able to construct a B from a A if B adds more
>> non-static data members?
>>
>
> One option is to simply define a constructor in B which takes A.
> Otherwise, it would be the same case when you create a class with a membe=
r
> which the constructor does not initialize. Otherwise one exception could =
be
> made for constructors so that they can be redefined in the new class. Thi=
s
> probably makes sense and it shoudn't be possible to break something (unle=
ss
> one creates a constructor which does not initialize some fields which are
> assumed initialized by the original class.. but then I believe it's a
> reasonable risk).
>
> I suggest you try it and see how it works. Let me know if it is reasonabl=
e.
>
>
> As you want to inherit all the member functions from the underlying class=
,
>> it has a sens to concentrate on member functions. I don't understand why
>> friend functions could not follow the same schema.
>>
>
> Well, friend functions are not members, so if you allow copying them, you
> are allowing copying arbitrary non-member functions (which I approve of).
> The only problem with this is that it is a big change - on top of this
> proposal. Just that.
>
> Not exactly. The compiler can copy the friend functions because it is
> aware of these functions and so it could copy them.
>
>
> void foo(int);
>>
>> void foo(double) : using foo(int);
>>
>> to use an analogous syntax to the one in my proposal. Not sure if this i=
s
>> clearer, let me know.
>>
>> I believe I understand you now but I don't see how this could help.
>>
>
> Well, this would be the way to create the "trampolines" for non-member
> functions. When you copy a class, you specify just once from which class
> you are copying. The compiler can then apply the change to all member
> functions automatically.
>
> However, you still have to specify non-member functions manually, since
> the compiler cannot assume you want them all.
>
> I believe you could let the user copy non-member non-friend function by
> itself.
>
>
> and also to A (since C is a type-copy of a type-copy).
>>
>> The first Opaque proposal contained a implicit subsumption relation that
>> allowed that. I'm all for, but I believe the committee doesn't like
>> transitivity in conversions.
>>
>
> Well, it is not really transitivity. As in, the C to A transition does no=
t
> need an implicit transition from B. The user is explicitly creating the
> conversion operator. The data in C exists, so it can be copied directly.
> Maybe you mean transitivity in the sense that the compiler needs to
> remember that C is a copy of B in order for it to know that it is also a
> copy of A. In that case I agree.
>
> Yes this is the case. You are requesting the compiler to do the conversio=
n
> transitively.
>
>
> Vicente
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/edb42928-1e58-ee22-
> 79ce-0fedd07247f1%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/edb42928-1e=
58-ee22-79ce-0fedd07247f1%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BsJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7=
Ab%3DYbew%40mail.gmail.com.
--f403045dd9604a4623054520a069
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Dear Vicente,<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"l=
tr"><div><div>As in,
the compiler knows that the first piece of the class will be
the same as the original, and every new member is added at
the end.<span class=3D"gmail-m_8086149550023163907gmail-m_-1377=
447551499369339gmail-im"><br>
</span></div>
</div>
</div>
</blockquote></span>
So if we argree that internal conversions are needed from/to the
underlying type, the new strong type couldn't add any new non-stati=
c
data member :)<span class=3D"gmail-im"><br></span></blockquote><div><br=
></div><div>I'm not sure I agree fully, but in any case the ability to =
add new non-static data members is not something I feel strongly about at t=
he moment. It's something that can be added in a future proposal if the=
re should arise a need. =3D)<br><br></div><div>Maybe I'll just remove t=
his from the proposal for the moment.<br></div><div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,=
204,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cit=
e"><div dir=3D"ltr"><div><div>Yes, of course. What I mean is, you have crea=
ted a class
which can only create exact copies of it. If you need
additional changes, it will probably be easier to
strong-type the original again and create new trampolines
from that. This is what I mean by non-extendable.<br>
</div>
</div>
</div>
</blockquote></span>
Why? I don't understand.<span class=3D"gmail-im"><br></span></block=
quote></div><div>=C2=A0<br></div><div>It may be that I just have a differen=
t idea in my head on how <span class=3D"gmail-im">p0109 would work in pract=
ice. I just have a feeling that those strong typedefs could be hard to work=
with, but I may just have misunderstood some parts.<br></span><span class=
=3D"gmail-im"></span><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><spa=
n class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><div><=
div>I start to see what you mean. But still, if one could
add them, the copy would still "contain" an equival=
ent of
the original class at its beginning. It wouldn't be
guaranteed reinterpret_cast-able, but the fields would be
there anyway. The original representation is there - so to
me it could still be considered a strong-typedef
(stretching a bit the definition maybe).<br>
</div>
</div>
</div>
</div>
</blockquote></span>
Remember that you need conversions from both sides to implement the
trampolines.<span class=3D"gmail-im"><br></span></blockquote><div><br><=
/div><div>Well, in inheritance child classes can be converted to their pare=
nts automatically (even if they don't define a constructor that initial=
izes any new data they might have). If that can be done I don't see why=
this would be impossible for a copied class + a new non-static data member=
to do the same thing.<br><blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><=
div><div>Well, if only the public interface is available, than
adding new methods to it is pretty much equivalent with
creating non-member functions (since those work with
public interface). Then you might as well remove the
ability to add new member functions, since non-members
will do just fine and there's no need to have them as
members.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
People like member functions also ;-)<span class=3D"gmail-im"><br></spa=
n></blockquote><div><br></div><div>Eh, true. But every feature must be just=
ified by a use case! ;D (joking)<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"l=
tr"><div><div><div>template <typename C><br>
class ConvertBack : using C {<br>
</div>
</div>
</div>
</div>
</blockquote></span>
public:<span class=3D"gmail-im"><br></span></blockquote><br></div><div>=
=C2=A0Whoops!<br><span class=3D"gmail-im"></span><blockquote class=3D"gmail=
_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204=
,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite">=
<div dir=3D"ltr"><div><div><div>// Strong typedef of double with +,- conver=
tible to double<br>
struct MyDouble : using
ConvertBack<Minus<Plus<Wrap<<wbr>double>>&g=
t;>
{}<br>
<br>
</div>
</div>
</div>
</div>
</blockquote></span>
This example is already more complete. Thanks.<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>------------------------------<wbr>--------------</div>
</div>
</div>
</div>
</blockquote>
ConvertBack will convert to
Minus<Plus<Wrap<double>>> :(<br>
<br>
Maybe the conversion should be part of Wrap or wrap should provide a
underlying function as I have in my library.<br>
<br>
operator+ returns Plus<Wrap<double>> but we want MyInt
or MyDouble :(<br>
<br>
See below how you could return the Final class. <br><span class=3D"gmai=
l-im">
</span></blockquote><span class=3D"gmail-im"><blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra">
</div></div></blockquote></span>Not exactly!<br><br></div><div>I=
9;ll try to analyze MyDouble to explain how it works.<br><br></div><div>Wra=
p<double> I believe we both understand it. So now let's consider =
Plus<Wrap<double>>.<br><br>template <typename C><br>struc=
t Plus : using C { // changed to struct to avoid public<br>=C2=A0=C2=A0=C2=
=A0 Plus operator+(Plus other) { return Plus{t_ + other.t_}; }<br>};<br><br=
></div><div>So it copies the templated class, and adds the operator+ to it.=
So the class becomes the equivalent of:<br><br></div><div>struct Plus { //=
Equivalent of Plus<Wrap<double>><br><span class=3D"gmail-im">=
=C2=A0=C2=A0=C2=A0 using base_type =3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 Plus(const Plus & other) : t_(other.t_=
) {}<br>
=C2=A0=C2=A0=C2=A0 explicit Plus(double t) : t_(t) {}<br><br>=
</span>=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plus{t_ + oth=
er.t_}; }=C2=A0=C2=A0=C2=A0 <br>private:<br></div><div>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 double t_;<br></div><div>};<br><br></div><div>See?=
Now any mention of Wrap has disappeared, since we copied that. Wrap<dou=
ble>, the original class, has been replaced by Plus (since we are copyin=
g). After the minus, the same thing would happen:<br><br><div>struct Minus =
{ // Equivalent of struct Minus<Plus<Wrap<double>>><br><s=
pan class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 using base_type =3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 Minus(const Minus & other) : t_(other.=
t_) {}<br>
=C2=A0=C2=A0=C2=A0 explicit Minus(double t) : t_(t) {}<br><br=
></span>=C2=A0=C2=A0=C2=A0 Minus operator+(Minus other) { return Minus{t_ +=
other.t_}; }<br><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 Minus operator=
-(Minus other) { return Minus{t_ -
other.t_}; }</span>=C2=A0 <br>private:<br></div><div>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double t_;<br></div>};<br><br></div><d=
iv>And finally, the last step:<br></div><div><br><div>struct ConvertBack { =
// Equivalent of struct ConvertBack<Minus<Plus<Wrap<double>&=
gt;>><br><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 using base_type =
=3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 </span><span class=3D"gmail-im">ConvertBac=
k(const </span><span class=3D"gmail-im">ConvertBack & other) : t_(other=
..t_) {}<br>
=C2=A0=C2=A0=C2=A0 explicit </span><span class=3D"gmail-im">C=
onvertBack(double t) : t_(t) {}<br><br></span></div><div><span class=3D"gma=
il-im">=C2=A0=C2=A0=C2=A0 // From Plus originally<br></span></div><div>=C2=
=A0=C2=A0=C2=A0 ConvertBack operator+(ConvertBack other) { return ConvertBa=
ck{t_ + other.t_}; }<br></div><div>=C2=A0=C2=A0=C2=A0 // From Minus origina=
lly<br></div><div><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 </span><span =
class=3D"gmail-im">ConvertBack operator-(</span><span class=3D"gmail-im">Co=
nvertBack other) { return </span><span class=3D"gmail-im">ConvertBack{t_ -
other.t_}; }<br></span></div><div><span class=3D"gmail-im">=
=C2=A0=C2=A0=C2=A0 // From ConvertBack, unchanged, but using the typedef (b=
ase_type) made initially in Wrap<double><br></span></div><div><span c=
lass=3D"gmail-im">=C2=A0=C2=A0=C2=A0 operator base_type() { return t_; }</s=
pan> <br>private:<br></div><div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
double t_;<br></div>};<br><br></div><div>I hope this makes more sense to yo=
u.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">template <ty=
pename Final, typename C><br>
class AFct : using C {<br>
public:<br>
=C2=A0=C2=A0=C2=A0 friend Final aFct(Final other) { return Final{aFct(o=
ther.t_)}; }<br>
};
</blockquote><div><br></div><div>This could be a way, yes.<br><br><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><bloc=
kquote type=3D"cite"><div dir=3D"ltr"><div class=3D"gmail_extra">One option=
is to simply define a
constructor in B which takes A. Otherwise, it would be the
same case when you create a class with a member which the
constructor does not initialize. Otherwise one exception could
be made for constructors so that they can be redefined in the
new class. This probably makes sense and it shoudn't be
possible to break something (unless one creates a constructor
which does not initialize some fields which are assumed
initialized by the original class.. but then I believe it's a
reasonable risk).<br>
</div>
</div>
</blockquote></span>
I suggest you try it and see how it works. Let me know if it is
reasonable.<span class=3D"gmail-im"><br></span></blockquote><div><br></=
div><div>I'll try to work on this a bit then.<br><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><blockquote type=
=3D"cite"><div dir=3D"ltr"><div class=3D"gmail_extra"><div>Well, friend fun=
ctions are not members, so if you allow
copying them, you are allowing copying arbitrary non-member
functions (which I approve of). The only problem with this
is that it is a big change - on top of this proposal. Just
that.<br>
</div>
</div>
</div>
</blockquote></span>
Not exactly. The compiler can copy the friend functions because it
is aware of these functions and so it could copy them.<span class=3D"gm=
ail-im"><br></span></blockquote><div><br></div><div>This seems reasonable.<=
br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gma=
il-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div class=3D"gmail_extra=
">However, you still have to specify non-member functions
manually, since the compiler cannot assume you want them all.<br>
</div>
</div>
</blockquote></span>
I believe you could let the user copy non-member non-friend function
by itself.</blockquote><div><br></div><div>Yes. However, can you do thi=
s process on random non-member functions to change their parameters to othe=
r types? If not, why not? Are you constrained in doing this only in copied =
class and with functions taking/returning the original class, maybe? Why?<b=
r><br></div><div>I'm not sure what the answers should be.<br><br><block=
quote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1=
px solid rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im"><block=
quote type=3D"cite"><div dir=3D"ltr"><div class=3D"gmail_extra">Well, it is=
not really transitivity. As
in, the C to A transition does not need an implicit transition
from B. The user is explicitly creating the conversion
operator. The data in C exists, so it can be copied directly.
Maybe you mean transitivity in the sense that the compiler
needs to remember that C is a copy of B in order for it to
know that it is also a copy of A. In that case I agree.<br>
</div>
</div>
</blockquote></span>
Yes this is the case. You are requesting the compiler to do the
conversion transitively.<br></blockquote><div><br></div><div>Makes sens=
e. Then forget the idea =3D)<br><br></div><div>Best,<br></div><div>Eugenio<=
br></div></div></div> </div></div></div></div></div></div><div class=3D"gma=
il_extra"><br><div class=3D"gmail_quote">On Mon, Jan 2, 2017 at 6:48 PM, Vi=
cente J. Botet Escriba <span dir=3D"ltr"><<a href=3D"mailto:vicente.bote=
t@wanadoo.fr" target=3D"_blank">vicente.botet@wanadoo.fr</a>></span> wro=
te:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-=
left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><span class=3D"">
<div class=3D"m_8086149550023163907moz-cite-prefix">Le 02/01/2017 =C3=
=A0 13:31, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">Dear Vicente,<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex=
;border-left:1px solid rgb(204,204,204);padding-left:1ex">Eugenio,
I believe the use cases we have both in mind are quite
different, and so we don't reach to understand one to each
other.</blockquote>
<div><br>
</div>
<div>It seems so. I am available to try other forms of
communications if you want (chat, voice call) if you want. I'=
m
sorry I'm not being as clear as I want.<br>
</div>
</div>
</blockquote></span>
No problem. It is my fault also.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I have a questi=
on. Does
you copy class proposal needs to have the definition of the
copied class available?<br>
If yes, I don't think this could be acceptable.<br>
If the declaration is enough, the copied functions would
need at least an internal conversion to/from the underlying
type, isn't it?<span class=3D"m_8086149550023163907gmail-m_=
-1377447551499369339gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>My proposal does not need the definition. Yes, I suppose
an internal conversion would be needed. The internal
conversion would probably work similarly to how inheritance
works, even if adding non-static members was allowed. As in,
the compiler knows that the first piece of the class will be
the same as the original, and every new member is added at
the end.<span class=3D"m_8086149550023163907gmail-m_-1377447551=
499369339gmail-im"><br>
</span></div>
</div>
</div>
</blockquote></span>
So if we argree that internal conversions are needed from/to the
underlying type, the new strong type couldn't add any new non-stati=
c
data member :)<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-m_-1377447551499369339gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>B b;<br>
b.A::bar(5);<br>
<br>
</div>
</div>
</div>
</blockquote>
</span> Agreed. And the language let me do that even if
you find it could be bad practice. I don't see why your
copy approach wouldn't let me do that.<span class=3D"m_80=
86149550023163907gmail-m_-1377447551499369339gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>In my approach the old function is impossible to hide,
so I think that the two cases are different.<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>If in all these cases your answer is "t=
he
program will fail to compile, just copy the
class by hand" then I think the feature
would be severely limited in what it could
actually do.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> You are probably right, and the copy should copy
every thing and give access to everything internally. I
need some concrete examples to understand what this
possibility will solve.<span class=3D"m_8086149550023163907=
gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Well, for example, a library that wanted to create
strong typedefs of primitive types via wrappers and only
expose certain operations, without getters/setters ;)
I've added some code later to show you how a possible
implementation using this proposal.<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span cla=
ss=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div> If I understand correctly, you want to
hide the original completely, and just be
offered an easy way to bring back some of
its interface (via trampolines) to its
"wrapper", which would be the stron=
g
typedef. </div>
</div>
</div>
</div>
</blockquote>
</span> I wouldn't say hiding, just don't looking
inside the underlying type. I want to provide access
to it (when needed) but only as a whole.<span class=3D"m_=
8086149550023163907gmail-im"><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Possibly adding more public methods
only using the public interface, which
could be done just the same with
non-member methods. The end result is a
class that cannot be extended in any
meaningful way using any of the normal C++
facilities, since every juicy bit is
hidden. </div>
</div>
</div>
</div>
</blockquote>
</span> Why it is unusable? The class provide access
to everything you want.<span class=3D"m_80861495500231639=
07gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Classes don't always come with getters and setters
for every private field. Especially if the interface
they provide is a high level one. It happens often in
low-level code that you want to interact with the
underlying bits in very specific ways, but you don't
necessarily want to give that kind of access to users.
So creating a strong typedef of such a class while
adding a new mode of operation would be impossible, as
the copy won't have access to the underlying
implementation.<br>
<br>
Another could be when you have to types that you know
contain the same (private) data, but should expose
different public interfaces. Then you could first
create the class containing the data, and copy it two
times, each time exposing a different interface (which
would need access to the private data). Once again, I
unfortunately don't have a practical use case at the
moment. I just think it could be useful.<br>
<br>
</div>
<div>Still the code below is a good use-case I think,
since it would be needed to provide strong typedefs of
primitive types.<br>
</div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span c=
lass=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>Applying strong-typing again to a
strong-typed class would be useless as
access to internals would be the same, </di=
v>
</div>
</div>
</div>
</blockquote>
</span> You can strong-type again. I don't see the
trouble. E.g; you can have a energy strong-type and
have kinetic_energy, potential_energy and=C2=A0
heat_energy strong-type of energy.<br>
Typing and representation are two different things.
Strong types are just that. Share a representation
and have different types.<span class=3D"m_8086149550023=
163907gmail-im"><br>
</span></blockquote>
</div>
</div>
</div>
<br>
</div>
<div>Yes, of course. What I mean is, you have created a class
which can only create exact copies of it. If you need
additional changes, it will probably be easier to
strong-type the original again and create new trampolines
from that. This is what I mean by non-extendable.<br>
</div>
</div>
</div>
</blockquote></span>
Why? I don't understand.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>aside from possibly adding more data (if
needed) in the public attributes, since only
those are editable. This would also prevent
encapsulation of new data. If not, it would
just mean that the feature wouldn't be used i=
n
a composable way.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe now that strong-type shouldn't add any
new non-static data member</blockquote>
<div><br>
</div>
<div>I start to see what you mean. But still, if one could
add them, the copy would still "contain" an equival=
ent of
the original class at its beginning. It wouldn't be
guaranteed reinterpret_cast-able, but the fields would be
there anyway. The original representation is there - so to
me it could still be considered a strong-typedef
(stretching a bit the definition maybe).<br>
</div>
</div>
</div>
</div>
</blockquote></span>
Remember that you need conversions from both sides to implement the
trampolines.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>Is there any other reason why you don't like the idea?=
<br>
</div>
</div>
</div>
</div>
</blockquote></span>
No, but it is enough. <br><span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>A feature that creates a non-extendable
object is like a dead-end.<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> I must agree with your last sentence, but I
don't think the strong-types I'm suggesting are
non-extendable?<span class=3D"m_8086149550023163907gmail-im=
"></span> <br>
</blockquote>
</div>
<div><br>
</div>
<div>Well, if only the public interface is available, than
adding new methods to it is pretty much equivalent with
creating non-member functions (since those work with
public interface). Then you might as well remove the
ability to add new member functions, since non-members
will do just fine and there's no need to have them as
members.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
People like member functions also ;-)<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>But wrappers can be made in a separate
library. Why should they be included in the
proposal? As long as the proposal allows
them, a library only needs to be made once
(and if not needed by someone, not used).<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> We need some probe of concept applied to
concrete examples we want to solve. I believe a strong
type feature must solve the builtin type case. If your
proposal is not a strong type proposal, then forget my
comments.<span class=3D"m_8086149550023163907gmail-im"><br>
</span></blockquote>
</div>
<div><span class=3D"m_8086149550023163907gmail-im"></span><br>
</div>
<div>This is how I would practically solve the primitive
types problem using my proposal:<br>
<br>
------------------------------<wbr>------------<br>
<br>
// library.hpp<br>
<br>
template <typename T><br>
class Wrap {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 using base_type =
=3D T;<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Wrap(const Wrap &a=
mp; other) : t_(other.t_) {}<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 explicit Wrap(T t)=
: t_(t) {}<br>
=C2=A0=C2=A0=C2=A0 <br>
=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 T t_;<br>
};<br>
<br>
template <typename C><br>
class ConvertBack : using C {<br>
</div>
</div>
</div>
</div>
</blockquote></span>
public:<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>=C2=A0=C2=A0=C2=A0 operator base_type() { return t_; }<br>
};<br>
<br>
template <typename C><br>
class Plus : using C {<br>
</div>
</div>
</div>
</div>
</blockquote></span>
public:<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plu=
s{t_ +
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Minus : using C {<br>
=C2=A0=C2=A0=C2=A0 Minus operator-(Minus other) { return Minu=
s{t_ -
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Prod : using C {<br>
=C2=A0=C2=A0=C2=A0 Prod operator+(Prod other) { return Prod{t=
_ *
other.t_}; }<br>
};<br>
<br>
template <typename C><br>
class Div : using C {<br>
=C2=A0=C2=A0=C2=A0 Div operator/(Div other) { return Div{t_ /=
other.t_};
}<br>
};<br>
<br>
template <typename T><br>
using Arithmetic =3D
Div<Prod<Minus<Plus<Wrap<T>>>><wbr=
>>;<br>
<br>
// .... and so on<br>
<br>
// usercode.cpp<br>
<br>
#include "library.hpp"<br>
<br>
// Strong typedef of int with +,-,/,*<br>
struct MyInt : using Arithmetic<int> {}<br>
<br>
// Strong typedef of double with +,- convertible to double<br=
>
struct MyDouble : using
ConvertBack<Minus<Plus<Wrap<<wbr>double>>&g=
t;>
{}<br>
<br>
</div>
</div>
</div>
</div>
</blockquote></span>
This example is already more complete. Thanks.<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>------------------------------<wbr>--------------</div>
</div>
</div>
</div>
</blockquote>
ConvertBack will convert to
Minus<Plus<Wrap<double>>> :(<br>
<br>
Maybe the conversion should be part of Wrap or wrap should provide a
underlying function as I have in my library.<br>
<br>
operator+ returns Plus<Wrap<double>> but we want MyInt
or MyDouble :(<br>
<br>
See below how you could return the Final class. <br><span class=3D"">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">If there's something missing you'=
;d like
to see how I'd do, let me know. Of course verbosity depends o=
n
granularity. If all operations need to be manually selected
you'll have lots of classes. If the granularity required is
less each class could add more operators at once.<br>
<br>
</div>
<div class=3D"gmail_extra">Note that you need access to privates
to be able to do this, so this could be an use-case for that.<br>
</div>
</div>
</blockquote></span>
I like the idea and yes it needs access to the private data. However
if we want to be able to provide the conversion to the underlying
type, it seems that the underlying data=C2=A0 is no more private anymor=
e
and should at least be read. To be fair, I have never created strong
types for classes that are not builtin types, or that are not copied
completely. If the function you want to add modifies only part of
the underlying type then either the underlying type provides already
this possibility, or the new type would need access to the private
part as you propose.<br>
<br>
I would need to see how I could adapt my Opaque library with this
language feature and see if it could be more simple. I will try with
private and without access.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">A problem that is not tackled in this
code and that we are also discussing is what to do with
non-member functions (that could possibly take base_type as
input). That depends on how non-member functions will be
handled in the proposals. If they can be handled I would
actually be happier.<br>
</div>
</div>
</blockquote></span>
template <typename Final, typename C><br>
class AFct : using C {<br>
public:<br>
=C2=A0=C2=A0=C2=A0 friend Final aFct(Final other) { return Final{aFct(o=
ther.t_)}; }<br>
};
<span class=3D""><blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"=
m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>Forcing the user to inherit to add more
data adds inheritance, which means that types
are now implicitly convertible (to at least a
common base). I don't think this is desirable=
..
I think strong typing should work on its own.<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> How then you will be able to construct a B from a A
if B adds more non-static data members?<span class=3D"m_8086149=
550023163907gmail-im"><br>
</span></blockquote>
</div>
<div class=3D"gmail_extra"><br>
</div>
<div class=3D"gmail_extra">One option is to simply define a
constructor in B which takes A. Otherwise, it would be the
same case when you create a class with a member which the
constructor does not initialize. Otherwise one exception could
be made for constructors so that they can be redefined in the
new class. This probably makes sense and it shoudn't be
possible to break something (unless one creates a constructor
which does not initialize some fields which are assumed
initialized by the original class.. but then I believe it's a
reasonable risk).<br>
</div>
</div>
</blockquote></span>
I suggest you try it and see how it works. Let me know if it is
reasonable.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">As you want to =
inherit
all the member functions from the underlying class, it has a
sens to concentrate on member functions. I don't understand
why friend functions could not follow the same schema.<span cla=
ss=3D"m_8086149550023163907gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Well, friend functions are not members, so if you allow
copying them, you are allowing copying arbitrary non-member
functions (which I approve of). The only problem with this
is that it is a big change - on top of this proposal. Just
that.<br>
</div>
</div>
</div>
</blockquote></span>
Not exactly. The compiler can copy the friend functions because it
is aware of these functions and so it could copy them.<span class=3D"">=
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra">
<div><span class=3D"m_8086149550023163907gmail-im"><br>
</span><span class=3D"m_8086149550023163907gmail-im"></span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>void foo(int);<br>
<br>
</div>
<div>void foo(double) : using foo(int);<br>
<br>
</div>
<div>to use an analogous syntax to the one
in my proposal. Not sure if this is
clearer, let me know.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> I believe I understand you now but I don't see ho=
w
this could help.<span class=3D"m_8086149550023163907gmail-im"=
><br>
</span></blockquote>
=C2=A0</div>
</div>
<div class=3D"gmail_extra">Well, this would be the way to create
the "trampolines" for non-member functions. When you co=
py a
class, you specify just once from which class you are copying.
The compiler can then apply the change to all member functions
automatically.<br>
<br>
However, you still have to specify non-member functions
manually, since the compiler cannot assume you want them all.<br>
</div>
</div>
</blockquote></span>
I believe you could let the user copy non-member non-friend function
by itself.<span class=3D""><br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"><span class=3D"m_8086149550023163907gmai=
l-im"><br>
</span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"=
m_8086149550023163907gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>and also to A (since C is a type-copy
of a type-copy).<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> The first Opaque proposal contained a implicit
subsumption relation that allowed that. I'm all for, but I
believe the committee doesn't like transitivity in
conversions.<span class=3D"m_8086149550023163907gmail-im"><br>
</span></blockquote>
<br>
</div>
<div class=3D"gmail_extra">Well, it is not really transitivity. As
in, the C to A transition does not need an implicit transition
from B. The user is explicitly creating the conversion
operator. The data in C exists, so it can be copied directly.
Maybe you mean transitivity in the sense that the compiler
needs to remember that C is a copy of B in order for it to
know that it is also a copy of A. In that case I agree.<br>
</div>
</div>
</blockquote></span>
Yes this is the case. You are requesting the compiler to do the
conversion transitively.<br>
<br>
<br>
Vicente
</div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/edb42928-1e58-ee22-79ce-0fedd07247f1%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/edb4=
2928-1e58-ee22-<wbr>79ce-0fedd07247f1%40wanadoo.fr</a><wbr>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BsJCyDr4sVhXK-9c9cn0JOdaWt7=
Fr1ejiCBVT7Ab%3DYbew%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab%3DYbew%40mail.gmail.com</a>.<br />
--f403045dd9604a4623054520a069--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Mon, 2 Jan 2017 23:36:27 +0100
Raw View
This is a multi-part message in MIME format.
--------------693BE2068D34A75E7098A930
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 02/01/2017 =C3=A0 19:21, Eugenio Bargiacchi a =C3=A9crit :
> Dear Vicente,
>
>> As in, the compiler knows that the first piece of the class will
>> be the same as the original, and every new member is added at the
>> end.
> So if we argree that internal conversions are needed from/to the
> underlying type, the new strong type couldn't add any new
> non-static data member :)
>
>
> I'm not sure I agree fully, but in any case the ability to add new=20
> non-static data members is not something I feel strongly about at the=20
> moment. It's something that can be added in a future proposal if there=20
> should arise a need. =3D)
>
> Maybe I'll just remove this from the proposal for the moment.
Great.
>
>> I start to see what you mean. But still, if one could add them,
>> the copy would still "contain" an equivalent of the original
>> class at its beginning. It wouldn't be guaranteed
>> reinterpret_cast-able, but the fields would be there anyway. The
>> original representation is there - so to me it could still be
>> considered a strong-typedef (stretching a bit the definition maybe).
> Remember that you need conversions from both sides to implement
> the trampolines.
>
>
> Well, in inheritance child classes can be converted to their parents=20
> automatically (even if they don't define a constructor that=20
> initializes any new data they might have). If that can be done I don't=20
> see why this would be impossible for a copied class + a new non-static=20
> data member to do the same thing.
You need to construct a derived from a base. If derived contains more=20
data you can not do it correctly.
>
>> // Strong typedef of double with +,- convertible to double
>> struct MyDouble : using ConvertBack<Minus<Plus<Wrap<double>>>> {}
>>
> This example is already more complete. Thanks.
>> --------------------------------------------
> ConvertBack will convert to Minus<Plus<Wrap<double>>> :(
>
> Maybe the conversion should be part of Wrap or wrap should provide
> a underlying function as I have in my library.
>
> operator+ returns Plus<Wrap<double>> but we want MyInt or MyDouble :(
>
> See below how you could return the Final class.
>
> Not exactly!
>
> I'll try to analyze MyDouble to explain how it works.
>
> Wrap<double> I believe we both understand it. So now let's consider=20
> Plus<Wrap<double>>.
>
> template <typename C>
> struct Plus : using C { // changed to struct to avoid public
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> };
>
> So it copies the templated class, and adds the operator+ to it. So the=20
> class becomes the equivalent of:
>
> struct Plus { // Equivalent of Plus<Wrap<double>>
> using base_type =3D double;
>
> Plus(const Plus & other) : t_(other.t_) {}
> explicit Plus(double t) : t_(t) {}
>
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> private:
> double t_;
> };
>
> See? Now any mention of Wrap has disappeared, since we copied that.=20
> Wrap<double>, the original class, has been replaced by Plus (since we=20
> are copying). After the minus, the same thing would happen:
>
> struct Minus { // Equivalent of struct Minus<Plus<Wrap<double>>>
> using base_type =3D double;
>
> Minus(const Minus & other) : t_(other.t_) {}
> explicit Minus(double t) : t_(t) {}
>
> Minus operator+(Minus other) { return Minus{t_ + other.t_}; }
> Minus operator-(Minus other) { return Minus{t_ - other.t_}; }
> private:
> double t_;
> };
>
> And finally, the last step:
>
> struct ConvertBack { // Equivalent of struct=20
> ConvertBack<Minus<Plus<Wrap<double>>>>
> using base_type =3D double;
>
> ConvertBack(const ConvertBack & other) : t_(other.t_) {}
> explicit ConvertBack(double t) : t_(t) {}
>
> // From Plus originally
> ConvertBack operator+(ConvertBack other) { return ConvertBack{t_ +=20
> other.t_}; }
> // From Minus originally
> ConvertBack operator-(ConvertBack other) { return ConvertBack{t_ -=20
> other.t_}; }
> // From ConvertBack, unchanged, but using the typedef (base_type)=20
> made initially in Wrap<double>
> operator base_type() { return t_; }
> private:
> double t_;
> };
>
> I hope this makes more sense to you.
Yes. I was missing all the copies and I mixed base_type as the base type=20
of ConvertBack. Sorry for reading your code too quickly.
I start liking your feature more and more. It could really help to make=20
easier to define opaque types.
The usage of the previous example is as if your copied classes were=20
mixins of the copied base class adding some additional functions.=20
Unfortunately we can not add more data due to the need for the double=20
conversion.
Note how
template <typename C>
struct Plus : using C {
Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
};
is close to p0109
template <typename C>
using Plus : private C {
Plus operator+(Plus x, Plus y) =3D default;
};
>
>
>> However, you still have to specify non-member functions manually,
>> since the compiler cannot assume you want them all.
> I believe you could let the user copy non-member non-friend
> function by itself.
>
>
> Yes. However, can you do this process on random non-member functions=20
> to change their parameters to other types?
IMO, you could change any function that has an underlying type as=20
parameter or return type using the trampoline idea. The problem is just=20
that the user needs to select the functions to default the generation of=20
the trampoline generation.
> If not, why not? Are you constrained in doing this only in copied=20
> class and with functions taking/returning the original class, maybe? Why?
No. You could substitute any type T by a type U if U(T(u)) =3D=3D u as the=
=20
trampoline is doing just this double conversion. The particularity of=20
opaque types is that the conversion costs nothing as both classes share=20
the same representation. For other types, the cost of the conversions=20
could be more visible.
>
> I'm not sure what the answers should be.
Vicente
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/08154fe2-11b8-dc7f-f13c-4a45e52a8c88%40wanadoo.f=
r.
--------------693BE2068D34A75E7098A930
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 02/01/2017 =C3=A0 19:21, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">Dear Vicente,<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><s=
pan
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>As in, the compiler knows that the first piece of
the class will be the same as the original, and
every new member is added at the end.<span
class=3D"gmail-m_8086149550023163907gmail-m_-13774475=
51499369339gmail-im"><br>
</span></div>
</div>
</div>
</blockquote>
</span> So if we argree that internal conversions are needed
from/to the underlying type, the new strong type couldn't add
any new non-static data member :)<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>I'm not sure I agree fully, but in any case the ability to
add new non-static data members is not something I feel
strongly about at the moment. It's something that can be added
in a future proposal if there should arise a need. =3D)<br>
<br>
</div>
<div>Maybe I'll just remove this from the proposal for the
moment.<br>
</div>
</div>
</blockquote>
Great.<br>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr"><span class=3D"gmail-im"></span><br>
<span class=3D"gmail-im"></span>
<div><span class=3D"gmail-im"></span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>I start to see what you mean. But still, if
one could add them, the copy would still
"contain" an equivalent of the original class at
its beginning. It wouldn't be guaranteed
reinterpret_cast-able, but the fields would be
there anyway. The original representation is
there - so to me it could still be considered a
strong-typedef (stretching a bit the definition
maybe).<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> Remember that you need conversions from both sides
to implement the trampolines.<span class=3D"gmail-im"><br>
</span></blockquote>
<div><br>
</div>
<div>Well, in inheritance child classes can be converted to
their parents automatically (even if they don't define a
constructor that initializes any new data they might have).
If that can be done I don't see why this would be impossible
for a copied class + a new non-static data member to do the
same thing.<br>
</div>
</div>
</div>
</blockquote>
You need to construct a derived from a base. If derived contains
more data you can not do it correctly.<br>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div><br>
<div><span class=3D"gmail-im"></span>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>// Strong typedef of double with +,-
convertible to double<br>
struct MyDouble : using
ConvertBack<Minus<Plus<Wrap<<wbr>do=
uble>>>>
{}<br>
<br>
</div>
</div>
</div>
</div>
</blockquote>
</span> This example is already more complete. Thanks.<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>------------------------------<wbr>-----------=
---</div>
</div>
</div>
</div>
</blockquote>
ConvertBack will convert to
Minus<Plus<Wrap<double>>> :(<br>
<br>
Maybe the conversion should be part of Wrap or wrap
should provide a underlying function as I have in my
library.<br>
<br>
operator+ returns Plus<Wrap<double>> but we
want MyInt or MyDouble :(<br>
<br>
See below how you could return the Final class. <br>
<span class=3D"gmail-im"> </span></blockquote>
<span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra"> </div>
</div>
</blockquote>
</span>Not exactly!<br>
<br>
</div>
<div>I'll try to analyze MyDouble to explain how it works.<br>
<br>
</div>
<div>Wrap<double> I believe we both understand it. So
now let's consider Plus<Wrap<double>>.<br>
<br>
template <typename C><br>
struct Plus : using C { // changed to struct to avoid
public<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plus{t=
_ +
other.t_}; }<br>
};<br>
<br>
</div>
<div>So it copies the templated class, and adds the
operator+ to it. So the class becomes the equivalent of:<br>
<br>
</div>
<div>struct Plus { // Equivalent of
Plus<Wrap<double>><br>
<span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 using base_type =
=3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 Plus(const Plus & other) : t_(other.=
t_) {}<br>
=C2=A0=C2=A0=C2=A0 explicit Plus(double t) : t_(t) {}<br>
<br>
</span>=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return=
Plus{t_ +
other.t_}; }=C2=A0=C2=A0=C2=A0 <br>
private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double t_;<br>
</div>
<div>};<br>
<br>
</div>
<div>See? Now any mention of Wrap has disappeared, since we
copied that. Wrap<double>, the original class, has
been replaced by Plus (since we are copying). After the
minus, the same thing would happen:<br>
<br>
<div>struct Minus { // Equivalent of struct
Minus<Plus<Wrap<double>>><br>
<span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 using base_type=
=3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 Minus(const Minus & other) : t_(ot=
her.t_) {}<br>
=C2=A0=C2=A0=C2=A0 explicit Minus(double t) : t_(t) {}<br=
>
<br>
</span>=C2=A0=C2=A0=C2=A0 Minus operator+(Minus other) { re=
turn
Minus{t_ + other.t_}; }<br>
<span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 Minus operator-=
(Minus other)
{ return Minus{t_ - other.t_}; }</span>=C2=A0 <br>
private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double t_;<br=
>
</div>
};<br>
<br>
</div>
<div>And finally, the last step:<br>
</div>
<div><br>
<div>struct ConvertBack { // Equivalent of struct
ConvertBack<Minus<Plus<Wrap<double>>>&=
gt;<br>
<span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 using base_type=
=3D double;<br>
<br>
=C2=A0=C2=A0=C2=A0 </span><span class=3D"gmail-im">Conver=
tBack(const </span><span
class=3D"gmail-im">ConvertBack & other) :
t_(other.t_) {}<br>
=C2=A0=C2=A0=C2=A0 explicit </span><span class=3D"gmail-i=
m">ConvertBack(double
t) : t_(t) {}<br>
<br>
</span></div>
<div><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 // From Plus=
originally<br>
</span></div>
<div>=C2=A0=C2=A0=C2=A0 ConvertBack operator+(ConvertBack oth=
er) { return
ConvertBack{t_ + other.t_}; }<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 // From Minus originally<br>
</div>
<div><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 </span><span
class=3D"gmail-im">ConvertBack operator-(</span><span
class=3D"gmail-im">ConvertBack other) { return </span><sp=
an
class=3D"gmail-im">ConvertBack{t_ - other.t_}; }<br>
</span></div>
<div><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 // From Conv=
ertBack,
unchanged, but using the typedef (base_type) made
initially in Wrap<double><br>
</span></div>
<div><span class=3D"gmail-im">=C2=A0=C2=A0=C2=A0 operator bas=
e_type() {
return t_; }</span> <br>
private:<br>
</div>
<div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double t_;<br=
>
</div>
};<br>
<br>
</div>
<div>I hope this makes more sense to you.<br>
</div>
</div>
</div>
</div>
</blockquote>
Yes. I was missing all the copies and I mixed base_type as the base
type of ConvertBack. Sorry for reading your code too quickly. <br>
<br>
I start liking your feature more and more. It could really help to
make easier to define opaque types. <br>
<br>
The usage of the previous example is as if your copied classes were
mixins of the copied base class adding some additional functions.
Unfortunately we can not add more data due to the need for the
double conversion.<br>
<br>
Note how <br>
<br>
template <typename C><br>
struct Plus : using C {<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plus{t_ + other.=
t_}; }<br>
};<br>
<br>
is close to=C2=A0 p0109<br>
<br>
template <typename C><br>
using Plus : private C {<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus x, Plus y) =3D default;<br>
};<br>
<br>
<br>
<br>
<br>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px
0px 0px 0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra">However, you still
have to specify non-member functions
manually, since the compiler cannot assume
you want them all.<br>
</div>
</div>
</blockquote>
</span> I believe you could let the user copy
non-member non-friend function by itself.</blockquote=
>
<div><br>
</div>
<div>Yes. However, can you do this process on random
non-member functions to change their parameters to
other types? </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
IMO, you could change any function that has an underlying type as
parameter or return type using the trampoline idea. The problem is
just that the user needs to select the functions to default the
generation of the trampoline generation.=C2=A0 <br>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>If not, why not? Are you constrained in doing
this only in copied class and with functions
taking/returning the original class, maybe? Why?<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
No. You could substitute any type T by a type U if U(T(u)) =3D=3D u as
the trampoline is doing just this double conversion. The
particularity of opaque types is that the conversion costs nothing
as both classes share the same representation. For other types, the
cost of the conversions could be more visible.<br>
<blockquote
cite=3D"mid:CAHfn=3D+sJCyDr4sVhXK-9c9cn0JOdaWt7Fr1ejiCBVT7Ab=3DYbew@mail.gm=
ail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div><br>
</div>
<div>I'm not sure what the answers should be.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/08154fe2-11b8-dc7f-f13c-4a45e52a8c88%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/08154fe2-11b8-dc7f-f13c-4a45e52a8c88=
%40wanadoo.fr</a>.<br />
--------------693BE2068D34A75E7098A930--
.
Author: iontodirel@gmail.com
Date: Mon, 2 Jan 2017 23:52:49 -0800 (PST)
Raw View
------=_Part_4892_606807995.1483429969374
Content-Type: multipart/alternative;
boundary="----=_Part_4893_1134882174.1483429969375"
------=_Part_4893_1134882174.1483429969375
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
What about a syntax like this:
struct Foo
{
};
typealias int int_;
typealias Foo Foo2;
On Monday, December 19, 2016 at 3:04:48 AM UTC-8, sval...@gmail.com wrote:
>
> This is a stub proposal on strong typedefs, i.e. types that work in the=
=20
> exact same way, but allow separate overloading. Other papers and proposal=
s=20
> exist, but I've tried a different approach that tries to mimic a more=20
> inheritance-like syntax which might be more intuitive. The full text can =
be=20
> found online at https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.=
=20
> Thanks in advance for your comments.
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing=20
> functionality
> while wrapping it in a new type, without the burden of inheritance and to=
=20
> allow
> function overloads on syntactically identical but semantically different=
=20
> types
> (also known as *strong typedef*).
>
> The approach taken should be simple to implement and be applicable to=20
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but=20
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending on=
=20
> context
> have currently no simple way to indicate the semantic differences. Sinc=
e=20
> a
> `typedef` does not allow multiple overloads on new typedef types - sinc=
e=20
> they
> are still the "old" type - they have to resort to imperfect techniques,=
=20
> such
> as copying, wrapping or inheriting the needed type. Examples:=20
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather th=
an
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste=20
> alternative.
> This can result in very deep hierarchies of types which should really=
=20
> not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but=20
> partially
> extend it with context-specific methods. Examples: search for=20
> "`std::vector`
> inheritance" yields many results of users trying to maintain the origin=
al
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type. However=
,=20
> this
> leaves no space to implement overloads that are context-specific. Nor a=
=20
> type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a=20
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even=20
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to=20
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in=20
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original interfac=
e=20
> in
> order to be able to duplicate it correctly. Template methods, rvalue=20
> references,
> possibly undocumented methods which are required in order to allow the=20
> class to
> behave in the same way as before. This heightens the bar significantly fo=
r=20
> many
> users, since they may not know correctly how to duplicate an interface an=
d=20
> how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs=20
> discovered
> in one class must be fixed in the other class too. All new features=20
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and=20
> implementation
> of a given class just one time, and used multiple times to produce separa=
te
> classes.
>
> This approach is unfortunately not applicable to existing code, and is=20
> very hard
> to extend if one wants to copy a class but add additional functionality t=
o=20
> it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are=20
> unfortunately
> not applicable to previously existing code. For new code, they would=20
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible: variation=
s=20
> would
> need to be made through specialization, which itself requires copying=20
> existing
> code.
>
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language multiple=
=20
> times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f
> ),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf
> ),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
> ),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are=
=20
> named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private` ar=
e=20
> used
> in order to create a specific relation with the original type and how is=
=20
> the
> new type allowed to be cast back to the original type or be used in its=
=20
> place
> during overloads.
>
> This document shares many of the the same principles, for example (quotin=
g=20
> from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships such =
as
> > base classes underlying derived classes and integer types underlying=
=20
> enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We=20
> also do
> > not require that any enum type, reference type, array type, function=
=20
> type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple approach,=
=20
> where
> a new language feature is introduced with the same meaning and=20
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more simple=
=20
> to
> understand (as it simply matches already the already understood mechanics=
=20
> of
> creating a new, unique type from nothing), and no new rules for type=20
> conversion
> and selection on overloads have to be created.
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class is=
=20
> needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would=20
> inherit
> from the same classes its base class inherits from. All constructors woul=
d=20
> work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of Base,=
=20
> to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion operator=
s=20
> can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility were=
=20
> needed,
> one would only need to implement them once, since copying the produced ty=
pe
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
>
> In general the usual rules of `reinterpret_cast` apply to the copied=20
> classes
> with respect to their general classes, exactly as if the copied class had=
=20
> been
> implemented by hand.
>
> ### Overloads ###
>
> Duplicating an existing class should allow for new overloads on the new=
=20
> type,
> and no ambiguity between the copied class, the old class and other copied
> classes.
>
> ```cpp
> class Position : using std::pair<double, double> {};
> class Distance : using std::pair<double, double> {};
>
> Position operator+(const Position & p, const Distance & d) {
> return Position(p.first + d.first, p.second + d.second);
> }
>
> Distance operator+(const Distance & lhs, const Distance & rhs) {
> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
> }
>
> // ...
>
> Position p(1, 1);
> Distance d(1, 1);
>
> p + d; // OK
> d + d; // OK
> p + p; // Error
> ```
>
> ### Templated Class Copy ###
>
> The user might want to create a single templatized copy interface, and us=
e=20
> it
> multiple times. For example, one might want multiple copied classes which=
=20
> can
> convert to their original. This could be done as follows:
>
> ```cpp
> struct A { int x; };
>
> template <typename T>
> struct TemplatizedCopy : using T {
> static_assert(std::is_standard_layout<T>::value,
> "Can't use this with a non-standard-layout class");
>
> operator T&() { return *reinterpret_cast<T*>(this); }
> };
>
> // Could be used either via normal typedefs
> using Copy1 =3D TemplatizedCopy<A>;
>
> // Or via copy, depending on requirements.
> struct Copy2 : using TemplatizedCopy<A> {};
> ```
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating=20
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template parameters=
=20
> than
> the base class. Partial or full specializations of the base class can be=
=20
> allowed:
>
> ```cpp
> template <typename T, typename U>
> struct A {};
>
> template <typename T>
> struct B : using A<T, double> {};
>
> B<int> b;
> ```
>
> When the base class has partial specializations, only those who apply are=
=20
> copied
> to the copied class.
>
> ```cpp
> template <typename T, typename U>
> struct A { T t; U u; };
>
> template <typename U>
> struct A<double, U> { double y; U u; };
>
> template <typename T>
> struct A<T, int> { T t; char z; };
>
> template <typename T>
> struct B : using A<T, double> {};
>
> /* Equivalent to
>
> template <typename T>
> struct B { T t; double u; };
>
> template <>
> struct B<double> { double y; double u; };
>
> */
> ```
>
> The copied class can add additional specializations. Or specializations=
=20
> for a
> given class can copy another.
>
> ```cpp
> template <typename T>
> struct A { int x; };
>
> struct B { char c; };
>
> template <typename T>
> struct C : using A<T> {};
>
> template <>
> struct C<double> : using B {};
>
> template <>
> struct A<int> : using C<double> {};
>
> /* Equivalent to
>
> template<>
> struct A<int> { char c; };
>
> template <typename T>
> struct C { int x; };
>
> template <>
> struct C<double> { char c; };
>
> */
> ```
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because each=
=20
> copy
> would depend on the originals, rather than on the copied classes. A=20
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A;
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal `usin=
g`
> alias directive. `using class` is only valid when the left hand side has=
=20
> been
> defined as a copy of the right hand side.
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
> ### Substituting Existing Functionality (Optional) ###
>
> Ideally one may want to use most of an implementation for another class,=
=20
> but
> vary a certain number of methods. In this case, if `Copy` contains a memb=
er
> function that already exists in `Base`, then that implementation is=20
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of "interface"=
,=20
> where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed also=
=20
> alter
> behavior and/or variable types of non-modified member and non-member=20
> functions,
> since the new behavior could be either erroneous or ambiguous.
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types. Using t=
he
> extension that allows the modification of the copied types, this could=20
> allow for
> creation of numeric types where some operations are disabled as needed.
>
> ```cpp
> struct Id : using int {
> Id operator+(Id, Id) =3D delete;
> Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
> // Defining new operators with the old type can allow interoperativit=
y
> Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden as=
=20
> the
> generated copy is `final` (although it is allowed to keep copying the new=
ly
> created class).
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine=20
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
> Compatibility
> -------------
>
> As the syntax is new, no old code would be affected.
>
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/a0b3d113-7671-437e-9822-1072d5f3ad1d%40isocpp.or=
g.
------=_Part_4893_1134882174.1483429969375
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">What about a syntax like this:<br><br>struct Foo<br>{<div>=
};<br>typealias int int_;<div>typealias Foo Foo2;<br><br>On Monday, Decembe=
r 19, 2016 at 3:04:48 AM UTC-8, sval...@gmail.com wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr">This is a stub proposal on str=
ong typedefs, i.e. types that work in the exact same way, but allow separat=
e overloading. Other papers and proposals exist, but I've tried a diffe=
rent approach that tries to mimic a more inheritance-like syntax which migh=
t be more intuitive. The full text can be found online at <a href=3D"https:=
//github.com/Svalorzen/CppCopyProposal" target=3D"_blank" rel=3D"nofollow" =
onmousedown=3D"this.href=3D'https://www.google.com/url?q\x3dhttps%3A%2F=
%2Fgithub.com%2FSvalorzen%2FCppCopyProposal\x26sa\x3dD\x26sntz\x3d1\x26usg\=
x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQw';return true;" onclick=3D"this.hr=
ef=3D'https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalor=
zen%2FCppCopyProposal\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhul=
f7sjCIvww-EQKQw';return true;">https://github.com/Svalorzen/<wbr>CppCop=
yProposal.<br><br></a>I'm copying the text below. Thanks in advance for=
your comments.<br><br><span style=3D"font-family:courier new,monospace">Du=
plication and Extension of Existing Classes<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>Introduction<br>------------=
<br><br>This document describes a possible approach to duplicate existing f=
unctionality<br>while wrapping it in a new type, without the burden of inhe=
ritance and to allow<br>function overloads on syntactically identical but s=
emantically different types<br>(also known as *strong typedef*).<br><br>The=
approach taken should be simple to implement and be applicable to existing=
<br>code.<br><br>Optional sections are to be read as additional ideas that =
could be further<br>developed or completely ignored. They are mostly food f=
or thought, but included<br>for completeness.<br><br>Reasons<br>-------<br>=
<br>- Scientific libraries where a type has different behaviors depending o=
n context<br>=C2=A0 have currently no simple way to indicate the semantic d=
ifferences. Since a<br>=C2=A0 `typedef` does not allow multiple overloads o=
n new typedef types - since they<br>=C2=A0 are still the "old" ty=
pe - they have to resort to imperfect techniques, such<br>=C2=A0 as copying=
, wrapping or inheriting the needed type. Examples: coordinates in a<br>=C2=
=A0 plane (rectangular, polar), vectors of double (probabilities, values).<=
br>- Easier maintainability of code which is known to be the same, rather t=
han<br>=C2=A0 being copy-pasted.<br>- Avoiding misuse of inheritance in ord=
er to provide a copy-paste alternative.<br>=C2=A0 This can result in very d=
eep hierarchies of types which should really not have<br>=C2=A0 anything to=
do with each other.<br>- Enabling users to use an existing and presumably =
correct type but partially<br>=C2=A0 extend it with context-specific method=
s. Examples: search for "`std::vector`<br>=C2=A0 inheritance" yie=
lds many results of users trying to maintain the original<br>=C2=A0 interfa=
ce and functionality but add one or two methods.<br><br>The functionality s=
hould have the following requirements:<br><br>- Can be applied to existing =
code.<br>- Should limit dependencies between new and old type as much as po=
ssible.<br>- Should allow for partial extensions of the old code.<br><br>Al=
ternatives<br>------------<br><br>### Typedef / Using Directive ###<br><br>=
Using a type alias creates an alternative name for a single type. However, =
this<br>leaves no space to implement overloads that are context-specific. N=
or a type can<br>be extended in a simple way while keeping the old interfac=
e intact.<br><br>### Inheritance ###<br><br>Inheritance requires redefiniti=
on of all constructors, and creates a stricter<br>dependency between two cl=
asses than what is proposed here. Classes may be<br>converted to a common a=
ncestor even though that is undesired or even dangerous<br>in case of impli=
cit conversions.<br><br>Inheritance may also be unwanted in order to avoid =
risks linked to polymorphism<br>and freeing data structures where the base =
class does not have a virtual<br>destructor.<br><br>### Encapsulation with =
Manual Exposure of Needed Methods ###<br><br>This method obviously requires=
a great deal of code to be rewritten in order to<br>wrap every single meth=
od that the old class was exposing.<br><br>In addition one needs to have in=
timate knowledge of the original interface in<br>order to be able to duplic=
ate it correctly. Template methods, rvalue references,<br>possibly undocume=
nted methods which are required in order to allow the class to<br>behave in=
the same way as before. This heightens the bar significantly for many<br>u=
sers, since they may not know correctly how to duplicate an interface and h=
ow<br>to forward parameters to the old interface correctly.<br><br>The new =
code also must be maintained in case the old interface changes.<br><br>### =
Copying the Base Class ###<br><br>This can be useful, but requires all code=
to be duplicated, and thus<br>significantly increases the burden of mainta=
ining the code. All bugs discovered<br>in one class must be fixed in the ot=
her class too. All new features applied to<br>one class must be applied to =
the other too.<br><br>### Macro-expansion ###<br><br>Macro expansions can b=
e used in order to encode the interface and implementation<br>of a given cl=
ass just one time, and used multiple times to produce separate<br>classes.<=
br><br>This approach is unfortunately not applicable to existing code, and =
is very hard<br>to extend if one wants to copy a class but add additional f=
unctionality to it.<br><br>### Templates ###<br><br>Templates produce for e=
ach instantiation a separate type. They are unfortunately<br>not applicable=
to previously existing code. For new code, they would require the<br>creat=
ion of "fake" template parameters that would need to vary in orde=
r to<br>produce separate types.<br><br>In addition, class extension through=
templates is not possible: variations would<br>need to be made through spe=
cialization, which itself requires copying existing<br>code.<br><br>Previou=
s Work<br>-------------<br><br>Strong typedefs have already been proposed f=
or the C++ language multiple times<br>([N1706](<a href=3D"http://www.open-s=
td.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf" target=3D"_blank" rel=3D"=
nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\x3dht=
tp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn=
1706.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0=
VQ';return true;" onclick=3D"this.href=3D'http://www.google.com/url=
?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F=
2004%2Fn1706.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEGleYuUYy8G59_eDbn=
N11KwFn0VQ';return true;">http://www.open-std.<wbr>org/jtc1/sc22/wg21/d=
ocs/<wbr>papers/2004/n1706.pdf</a>),<br>[N1891](<a href=3D"http://www.open-=
std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf" target=3D"_blank" rel=3D=
"nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\x3dh=
ttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2F=
n1891.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1l=
mPA';return true;" onclick=3D"this.href=3D'http://www.google.com/ur=
l?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2=
F2005%2Fn1891.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_X=
y3fqKa1lmPA';return true;">http://www.open-std.<wbr>org/jtc1/sc22/wg21/=
docs/<wbr>papers/2005/n1891.pdf</a>),<br>[N3515](<a href=3D"http://www.open=
-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf" target=3D"_blank" rel=
=3D"nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\x=
3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013=
%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK=
7PtwMg';return true;" onclick=3D"this.href=3D'http://www.google.com=
/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpaper=
s%2F2013%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHA18OHTi46Xo80=
VTjRf_GK7PtwMg';return true;">http://www.open-std.<wbr>org/jtc1/sc22/wg=
21/docs/<wbr>papers/2013/n3515.pdf</a>),<br>[N3741](<a href=3D"https://isoc=
pp.org/files/papers/n3741.pdf)" target=3D"_blank" rel=3D"nofollow" onmoused=
own=3D"this.href=3D'https://www.google.com/url?q\x3dhttps%3A%2F%2Fisocp=
p.org%2Ffiles%2Fpapers%2Fn3741.pdf)\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjC=
NFsO-HZdSZm41tTzZev2nxIpJkHZA';return true;" onclick=3D"this.href=3D=
9;https://www.google.com/url?q\x3dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers=
%2Fn3741.pdf)\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nx=
IpJkHZA';return true;">https://isocpp.org/<wbr>files/papers/n3741.pdf)<=
/a>). These typedefs are named<br>*opaque typedefs*, and these papers try t=
o explore and define exactly the<br>behavior that such typedefs should and =
would have when used to create new<br>types. In particular, the keywords `p=
ublic`, `protected` and `private` are used<br>in order to create a specific=
relation with the original type and how is the<br>new type allowed to be c=
ast back to the original type or be used in its place<br>during overloads.<=
br><br>This document shares many of the the same principles, for example (q=
uoting from<br>N3741):<br><br>> - Consistent with restrictions imposed o=
n analogous relationships such as<br>>=C2=A0=C2=A0 base classes underlyi=
ng derived classes and integer types underlying enums,<br>>=C2=A0=C2=A0 =
an underlying type should be (1) complete and (2) not cv-quali=EF=AC=81ed. =
We also do<br>>=C2=A0=C2=A0 not require that any enum type, reference ty=
pe, array type, function type, or<br>>=C2=A0=C2=A0 pointer-to-member typ=
e be allowed as an underlying type.<br><br>However, this document tries to =
propose a possibly more simple approach, where<br>a new language feature is=
introduced with the same meaning and functionality as<br>if the user auton=
omously implemented a new class him/herself, matching the<br>original type =
completely. Thus, it should result for the user more simple to<br>understan=
d (as it simply matches already the already understood mechanics of<br>crea=
ting a new, unique type from nothing), and no new rules for type conversion=
<br>and selection on overloads have to be created.<br><br>Syntax<br>------<=
br><br>### Simple Case ###<br><br>Syntax could look something like this:<br=
><br>```cpp<br>class Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo " <<=
; x << "\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>struct Copy : using B=
ase {};<br><br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 =
public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout << =
"foo " << x << "\n"; }<br>=C2=A0=C2=A0=C2=
=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br>=
<br>*/<br>```<br><br>One cannot copy a class and inherit at the same time. =
If such a class is needed<br>one would need to create it by hand with the d=
esided functionality and<br>inheriting from the desired classes, as it woul=
d be done normally.<br><br>All method implementations would be the same. Th=
e copied class would inherit<br>from the same classes its base class inheri=
ts from. All constructors would work<br>in the same way.<br><br>### Adding =
New Functionality ###<br><br>Ideally one could specify additional methods, =
separate from that of Base, to add<br>upon the existing functionality.<br><=
br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout <=
;< "foo\n"; }<br>};<br><br>struct Derived : public Base {};<br=
><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cou=
t << "bar\n"; }<br>};<br><br>struct CopyDerived : using Der=
ived {};<br><br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0=
void foo() { std::cout << "foo\n"; }<br>=C2=A0=C2=A0=C2=A0=
void bar() { std::cout << "bar\n"; }<br>};<br><br>struct C=
opyDerived : public Base {};<br><br>*/<br>```<br><br>Only new methods need =
to be implemented for that class.<br><br>#### Interfacing with the Original=
Class ####<br><br>In order to interface with the original class, simple co=
nversion operators can<br>be added by the user explicitly at-will, in order=
to obtain the desired<br>interface. Note that if more types with this kind=
of compatibility were needed,<br>one would only need to implement them onc=
e, since copying the produced type<br>would copy the new, more compatible i=
nterface with it.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 publ=
ic:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br><br>=C2=A0=C2=
=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<=
br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 operator Base=
() { return Base{x, y}; }<br>};<br>```<br><br>`reinterpret_cast` may also b=
e used to convert back to the original class,<br>limited by the tool's =
already existing rules.<br><br>In general the usual rules of `reinterpret_c=
ast` apply to the copied classes<br>with respect to their general classes, =
exactly as if the copied class had been<br>implemented by hand.<br><br>### =
Overloads ###<br><br>Duplicating an existing class should allow for new ove=
rloads on the new type,<br>and no ambiguity between the copied class, the o=
ld class and other copied<br>classes.<br><br>```cpp<br>class Position : usi=
ng std::pair<double, double> {};<br>class Distance : using std::pair&=
lt;double, double> {};<br><br>Position operator+(const Position & p,=
const Distance & d) {<br>=C2=A0=C2=A0=C2=A0 return Position(p.first + =
d.first, p.second + d.second);<br>}<br><br>Distance operator+(const Distanc=
e & lhs, const Distance & rhs) {<br>=C2=A0=C2=A0=C2=A0 return Dista=
nce(lhs.first + rhs.first, lhs.second + rhs.second);<br>}<br><br>// ...<br>=
<br>Position p(1, 1);<br>Distance d(1, 1);<br><br>p + d; // OK<br>d + d; //=
OK<br>p + p; // Error<br>```<br><br>### Templated Class Copy ###<br><br>Th=
e user might want to create a single templatized copy interface, and use it=
<br>multiple times. For example, one might want multiple copied classes whi=
ch can<br>convert to their original. This could be done as follows:<br><br>=
```cpp<br>struct A { int x; };<br><br>template <typename T><br>struct=
TemplatizedCopy : using T {<br>=C2=A0=C2=A0=C2=A0 static_assert(std::is_<w=
br>standard_layout<T>::value,<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Ca=
n't use this with a non-standard-layout class");<br><br>=C2=A0=C2=
=A0=C2=A0 operator T&() { return *reinterpret_cast<T*>(this); }<b=
r>};<br><br>// Could be used either via normal typedefs<br>using Copy1 =3D =
TemplatizedCopy<A>;<br><br>// Or via copy, depending on requirements.=
<br>struct Copy2 : using TemplatizedCopy<A> {};<br>```<br><br>### Cop=
ying Template Classes ###<br><br>Since the construct is similar to inherita=
nce, the syntax for creating aliases<br>of templated classes could be the s=
ame:<br><br>```cpp<br>template <typename T><br>struct A {};<br><br>te=
mplate <typename T><br>struct B : using A<T> {};<br><br>B<in=
t> b;<br>```<br><br>The copied class must have the same number or less o=
f template parameters than<br>the base class. Partial or full specializatio=
ns of the base class can be allowed:<br><br>```cpp<br>template <typename=
T, typename U><br>struct A {};<br><br>template <typename T><br>st=
ruct B : using A<T, double> {};<br><br>B<int> b;<br>```<br><br>=
When the base class has partial specializations, only those who apply are c=
opied<br>to the copied class.<br><br>```cpp<br>template <typename T, typ=
ename U><br>struct A { T t; U u; };<br><br>template <typename U><b=
r>struct A<double, U> { double y; U u; };<br><br>template <typenam=
e T><br>struct A<T, int> { T t; char z; };<br><br>template <typ=
ename T><br>struct B : using A<T, double> {};<br><br>/* Equivalent=
to<br><br>template <typename T><br>struct B { T t; double u; };<br><=
br>template <><br>struct B<double> { double y; double u; };<br>=
<br>*/<br>```<br><br>The copied class can add additional specializations. O=
r specializations for a<br>given class can copy another.<br><br>```cpp<br>t=
emplate <typename T><br>struct A { int x; };<br><br>struct B { char c=
; };<br><br>template <typename T><br>struct C : using A<T> {};<=
br><br>template <><br>struct C<double> : using B {};<br><br>tem=
plate <><br>struct A<int> : using C<double> {};<br><br>/*=
Equivalent to<br><br>template<><br>struct A<int> { char c; };<=
br><br>template <typename T><br>struct C { int x; };<br><br>template =
<><br>struct C<double> { char c; };<br><br>*/<br>```<br><br>###=
Copying Multiple Dependent Classes ###<br><br>Copying multiple classes usi=
ng the simple syntax we have described can be<br>impossible if those classe=
s depend on one another. This is because each copy<br>would depend on the o=
riginals, rather than on the copied classes. A possible way<br>to specify s=
uch dependencies could be:<br><br>```cpp<br>struct A;<br><br>struct B {<br>=
=C2=A0=C2=A0=C2=A0 A * a;<br>};<br><br>struct A {<br>=C2=A0=C2=A0=C2=A0 B b=
;<br>};<br><br>struct C;<br><br>struct D : using B {<br>=C2=A0=C2=A0=C2=A0 =
using class C =3D A;<br>};<br><br>struct C : using A {<br>=C2=A0=C2=A0=C2=
=A0 using class D =3D B;<br>};<br><br>/* Equivalent to<br><br>struct C;<br>=
<br>struct D {<br>=C2=A0=C2=A0=C2=A0 C * a;<br>};<br><br>struct C {<br>=C2=
=A0=C2=A0=C2=A0 D b;<br>};<br><br>*/<br>```<br><br>`using class` has been u=
sed in order to disambiguate it from normal `using`<br>alias directive. `us=
ing class` is only valid when the left hand side has been<br>defined as a c=
opy of the right hand side.<br><br>In case of a template base class using a=
template second class, one could<br>specify different copies for certain s=
pecializations;<br><br>```cpp<br>template <typename T><br>struct A {}=
;<br><br>template <typename T><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A&=
lt;T> a;<br>};<br><br>template <typename T><br>struct C : using A&=
lt;T> {};<br><br>```<br><br>### Substituting Existing Functionality (Opt=
ional) ###<br><br>Ideally one may want to use most of an implementation for=
another class, but<br>vary a certain number of methods. In this case, if `=
Copy` contains a member<br>function that already exists in `Base`, then tha=
t implementation is substituted<br>in `Copy`. This may or may not be allowe=
d for attributes.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 void=
foo() { std::cout << "foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void=
bar() { std::cout << "bar\n"; }<br>};<br><br>struct Copy :=
using Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "b=
az\n"; }<br>};<br><br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=
=C2=A0=C2=A0 void foo() { std::cout << "baz\n"; }<br>=C2=A0=
=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>};<br>=
<br>*/<br>```<br><br>A side effect of this is that it could allow for some =
type of "interface", where<br>some base class could be defined as=
:<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 Base() =3D delete;<b=
r>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>};<br=
><br>struct Copy1 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;=
<br>=C2=A0=C2=A0=C2=A0 void baz();<br>=C2=A0=C2=A0=C2=A0 void foo() =3D del=
ete;<br>};<br><br>/* Equivalent to<br><br>struct Copy1 {<br>=C2=A0=C2=A0=C2=
=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=
=C2=A0 void baz();<br>};<br><br>*/<br><br>struct Copy2 : using Base {<br>=
=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><=
br>/*<br><br>Equivalent to<br><br>struct Copy2 {<br>=C2=A0=C2=A0=C2=A0 Copy=
2(int);<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();=
<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>*/<br>```<br><br>This featu=
re could however present problems when the members changed also alter<br>be=
havior and/or variable types of non-modified member and non-member function=
s,<br>since the new behavior could be either erroneous or ambiguous.<br><br=
>### Copying and Extending Primitive Types (Optional) ###<br><br>The same s=
yntax could be used in order to extend primitive types. Using the<br>extens=
ion that allows the modification of the copied types, this could allow for<=
br>creation of numeric types where some operations are disabled as needed.<=
br><br>```cpp<br>struct Id : using int {<br>=C2=A0=C2=A0=C2=A0 Id operator+=
(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 Id operator*(Id, Id) =3D delete;=
<br>=C2=A0=C2=A0=C2=A0 // Non-explicitly deleted operators keep their valid=
ity<br><br>=C2=A0=C2=A0=C2=A0 // Defining new operators with the old type c=
an allow interoperativity<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=
=C2=A0=C2=A0=C2=A0 // We can convert the copied type to the old one.<br>=C2=
=A0=C2=A0=C2=A0 operator int() { return (*this) * 2; }<br>};<br><br>/* Equi=
valent to<br><br>class Id final {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator/(Id lhs, Id rhs) { return =
Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id ope=
rator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }<br><br>=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { return v_ * 2; }<br>=C2=A0=C2=A0=
=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>};=
<br><br>*/<br>```<br><br>Note that when copying from a primitive types inhe=
ritance is forbidden as the<br>generated copy is `final` (although it is al=
lowed to keep copying the newly<br>created class).<br><br>### STL Traits (O=
ptional) ###<br><br>Traits could be included in the standard library in ord=
er to determine whether a<br>class is a copy of another, or if it has been =
derived from a copy<br>(copies/inheritances could be nested arbitrarily).<b=
r><br>```cpp<br>struct Base {};<br><br>struct Copy : using Base {};<br><br>=
static_assert(std::is_copy<<wbr>Copy, Base>::value);<br><br>struct Ch=
ildCopy : public Copy {};<br><br>struct CopyChildCopy : using ChildCopy {};=
<br><br>static_assert(std::is_copy_<wbr>base_of<Base, CopyChildCopy>:=
:value);<br>```<br><br>Compatibility<br>-------------<br><br>As the syntax =
is new, no old code would be affected.<br></span><br></div></blockquote></d=
iv></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/a0b3d113-7671-437e-9822-1072d5f3ad1d%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/a0b3d113-7671-437e-9822-1072d5f3ad1d=
%40isocpp.org</a>.<br />
------=_Part_4893_1134882174.1483429969375--
------=_Part_4892_606807995.1483429969374--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Tue, 3 Jan 2017 12:31:23 +0100
Raw View
--001a114757521ae1c905452f024b
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vicente,
> Well, in inheritance child classes can be converted to their parents
> automatically (even if they don't define a constructor that initializes a=
ny
> new data they might have). If that can be done I don't see why this would
> be impossible for a copied class + a new non-static data member to do the
> same thing.
>
> You need to construct a derived from a base. If derived contains more dat=
a
> you can not do it correctly.
>
Well not necessarily. There are classes that take fewer parameters than the
number of their members. There are classes that define a constructor with
no parameters, even though they have members. There are structs with no
constructor at all.
For example, if you copy a class and add, say, an std::vector, I'd say it
would be very easy to create the copy from the original, since the
std::vector can initialize itself very easily.
Yes. I was missing all the copies and I mixed base_type as the base type of
> ConvertBack. Sorry for reading your code too quickly.
>
> I start liking your feature more and more. It could really help to make
> easier to define opaque types.
>
I'm really glad you like it!
Note how
>
> template <typename C>
> struct Plus : using C {
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> };
>
> is close to p0109
>
> template <typename C>
> using Plus : private C {
> Plus operator+(Plus x, Plus y) =3D default;
> };
>
Yes. However, if non-member functions can be copied, I believe there should
exist a syntax to create them also outside the copied class. Suppose:
// From library
struct A {};
struct B : using A {}
// User defined
void foo(A a) {}
// How to define foo(B)?
The problem with this example is that when foo(A) is defined, B has already
been defined. The original case in p0109 is "easy" in the sense that the
non-member operators for primitive types are always defined before copies
can be made, so they can surely be seen in the copy.
One could argue that such a problem does not exist, since the new function
can be made template from the start and so apply to both A and B. Perhaps.
I'm just asking the question out of completeness, I'm not sure what the
answer should be.
If not, why not? Are you constrained in doing this only in copied class and
> with functions taking/returning the original class, maybe? Why?
>
> No. You could substitute any type T by a type U if U(T(u)) =3D=3D u as th=
e
> trampoline is doing just this double conversion. The particularity of
> opaque types is that the conversion costs nothing as both classes share t=
he
> same representation. For other types, the cost of the conversions could b=
e
> more visible.
I'm not sure that definition always holds, unfortunately. You'd have to
force them to have the same public interface, or else maybe the conversion
from U->T->U will work, but T has a different interface so they are not
compatible. Consider:
struct A {
A() : x_(0) {}
int x_;
};
struct B {
B(A a) : d_(5), i_(a.x_) {}
operator A() { return A{i_}; }
double d_;
int i_;
};
double foo(B b) {
return b.d_ + b.i_;
}
If you just follow the conversion rules, then you could convert foo(B) into
foo(A), since A(B(a)) =3D=3D a for any a. However, it would fail to compile=
as
of course B and A do not have the same interface. You'd have to guarantee
that when converting A to B that A has at least the same interface as B
(which is the same as copying, pretty much, even though it does not require
it since one could do this by hand). This includes static members,
typedefs, etc etc. It would also include non-member functions possibly - if
foo uses them.
The only way to practically make that check would be to just let the
compiler try, probably. Which would be equivalent to transforming foo into
a templated function. Which I'm not sure is going to get accepted.
Best,
Eugenio
On Tue, Jan 3, 2017 at 8:52 AM, <iontodirel@gmail.com> wrote:
> What about a syntax like this:
>
> struct Foo
> {
> };
> typealias int int_;
> typealias Foo Foo2;
>
>
> On Monday, December 19, 2016 at 3:04:48 AM UTC-8, sval...@gmail.com wrote=
:
>>
>> This is a stub proposal on strong typedefs, i.e. types that work in the
>> exact same way, but allow separate overloading. Other papers and proposa=
ls
>> exist, but I've tried a different approach that tries to mimic a more
>> inheritance-like syntax which might be more intuitive. The full text can=
be
>> found online at https://github.com/Svalorzen/CppCopyProposal.
>>
>> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text
>> below. Thanks in advance for your comments.
>>
>> Duplication and Extension of Existing Classes
>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>>
>> Introduction
>> ------------
>>
>> This document describes a possible approach to duplicate existing
>> functionality
>> while wrapping it in a new type, without the burden of inheritance and t=
o
>> allow
>> function overloads on syntactically identical but semantically different
>> types
>> (also known as *strong typedef*).
>>
>> The approach taken should be simple to implement and be applicable to
>> existing
>> code.
>>
>> Optional sections are to be read as additional ideas that could be furth=
er
>> developed or completely ignored. They are mostly food for thought, but
>> included
>> for completeness.
>>
>> Reasons
>> -------
>>
>> - Scientific libraries where a type has different behaviors depending on
>> context
>> have currently no simple way to indicate the semantic differences.
>> Since a
>> `typedef` does not allow multiple overloads on new typedef types -
>> since they
>> are still the "old" type - they have to resort to imperfect techniques=
,
>> such
>> as copying, wrapping or inheriting the needed type. Examples:
>> coordinates in a
>> plane (rectangular, polar), vectors of double (probabilities, values).
>> - Easier maintainability of code which is known to be the same, rather
>> than
>> being copy-pasted.
>> - Avoiding misuse of inheritance in order to provide a copy-paste
>> alternative.
>> This can result in very deep hierarchies of types which should really
>> not have
>> anything to do with each other.
>> - Enabling users to use an existing and presumably correct type but
>> partially
>> extend it with context-specific methods. Examples: search for
>> "`std::vector`
>> inheritance" yields many results of users trying to maintain the
>> original
>> interface and functionality but add one or two methods.
>>
>> The functionality should have the following requirements:
>>
>> - Can be applied to existing code.
>> - Should limit dependencies between new and old type as much as possible=
..
>> - Should allow for partial extensions of the old code.
>>
>> Alternatives
>> ------------
>>
>> ### Typedef / Using Directive ###
>>
>> Using a type alias creates an alternative name for a single type.
>> However, this
>> leaves no space to implement overloads that are context-specific. Nor a
>> type can
>> be extended in a simple way while keeping the old interface intact.
>>
>> ### Inheritance ###
>>
>> Inheritance requires redefinition of all constructors, and creates a
>> stricter
>> dependency between two classes than what is proposed here. Classes may b=
e
>> converted to a common ancestor even though that is undesired or even
>> dangerous
>> in case of implicit conversions.
>>
>> Inheritance may also be unwanted in order to avoid risks linked to
>> polymorphism
>> and freeing data structures where the base class does not have a virtual
>> destructor.
>>
>> ### Encapsulation with Manual Exposure of Needed Methods ###
>>
>> This method obviously requires a great deal of code to be rewritten in
>> order to
>> wrap every single method that the old class was exposing.
>>
>> In addition one needs to have intimate knowledge of the original
>> interface in
>> order to be able to duplicate it correctly. Template methods, rvalue
>> references,
>> possibly undocumented methods which are required in order to allow the
>> class to
>> behave in the same way as before. This heightens the bar significantly
>> for many
>> users, since they may not know correctly how to duplicate an interface
>> and how
>> to forward parameters to the old interface correctly.
>>
>> The new code also must be maintained in case the old interface changes.
>>
>> ### Copying the Base Class ###
>>
>> This can be useful, but requires all code to be duplicated, and thus
>> significantly increases the burden of maintaining the code. All bugs
>> discovered
>> in one class must be fixed in the other class too. All new features
>> applied to
>> one class must be applied to the other too.
>>
>> ### Macro-expansion ###
>>
>> Macro expansions can be used in order to encode the interface and
>> implementation
>> of a given class just one time, and used multiple times to produce
>> separate
>> classes.
>>
>> This approach is unfortunately not applicable to existing code, and is
>> very hard
>> to extend if one wants to copy a class but add additional functionality
>> to it.
>>
>> ### Templates ###
>>
>> Templates produce for each instantiation a separate type. They are
>> unfortunately
>> not applicable to previously existing code. For new code, they would
>> require the
>> creation of "fake" template parameters that would need to vary in order =
to
>> produce separate types.
>>
>> In addition, class extension through templates is not possible:
>> variations would
>> need to be made through specialization, which itself requires copying
>> existing
>> code.
>>
>> Previous Work
>> -------------
>>
>> Strong typedefs have already been proposed for the C++ language multiple
>> times
>> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/
>> 2004/n1706.pdf),
>> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pd=
f
>> ),
>> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pd=
f
>> ),
>> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are
>> named
>> *opaque typedefs*, and these papers try to explore and define exactly th=
e
>> behavior that such typedefs should and would have when used to create ne=
w
>> types. In particular, the keywords `public`, `protected` and `private`
>> are used
>> in order to create a specific relation with the original type and how is
>> the
>> new type allowed to be cast back to the original type or be used in its
>> place
>> during overloads.
>>
>> This document shares many of the the same principles, for example
>> (quoting from
>> N3741):
>>
>> > - Consistent with restrictions imposed on analogous relationships such
>> as
>> > base classes underlying derived classes and integer types underlying
>> enums,
>> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We
>> also do
>> > not require that any enum type, reference type, array type, function
>> type, or
>> > pointer-to-member type be allowed as an underlying type.
>>
>> However, this document tries to propose a possibly more simple approach,
>> where
>> a new language feature is introduced with the same meaning and
>> functionality as
>> if the user autonomously implemented a new class him/herself, matching t=
he
>> original type completely. Thus, it should result for the user more simpl=
e
>> to
>> understand (as it simply matches already the already understood mechanic=
s
>> of
>> creating a new, unique type from nothing), and no new rules for type
>> conversion
>> and selection on overloads have to be created.
>>
>> Syntax
>> ------
>>
>> ### Simple Case ###
>>
>> Syntax could look something like this:
>>
>> ```cpp
>> class Base {
>> public:
>> Base() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> struct Copy : using Base {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> public:
>> Copy() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> */
>> ```
>>
>> One cannot copy a class and inherit at the same time. If such a class is
>> needed
>> one would need to create it by hand with the desided functionality and
>> inheriting from the desired classes, as it would be done normally.
>>
>> All method implementations would be the same. The copied class would
>> inherit
>> from the same classes its base class inherits from. All constructors
>> would work
>> in the same way.
>>
>> ### Adding New Functionality ###
>>
>> Ideally one could specify additional methods, separate from that of Base=
,
>> to add
>> upon the existing functionality.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> };
>>
>> struct Derived : public Base {};
>>
>> struct Copy : using Base {
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : using Derived {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : public Base {};
>>
>> */
>> ```
>>
>> Only new methods need to be implemented for that class.
>>
>> #### Interfacing with the Original Class ####
>>
>> In order to interface with the original class, simple conversion
>> operators can
>> be added by the user explicitly at-will, in order to obtain the desired
>> interface. Note that if more types with this kind of compatibility were
>> needed,
>> one would only need to implement them once, since copying the produced
>> type
>> would copy the new, more compatible interface with it.
>>
>> ```cpp
>> struct Base {
>> public:
>> int x;
>>
>> private:
>> double y;
>> };
>>
>> struct Copy : using Base {
>> operator Base() { return Base{x, y}; }
>> };
>> ```
>>
>> `reinterpret_cast` may also be used to convert back to the original clas=
s,
>> limited by the tool's already existing rules.
>>
>> In general the usual rules of `reinterpret_cast` apply to the copied
>> classes
>> with respect to their general classes, exactly as if the copied class ha=
d
>> been
>> implemented by hand.
>>
>> ### Overloads ###
>>
>> Duplicating an existing class should allow for new overloads on the new
>> type,
>> and no ambiguity between the copied class, the old class and other copie=
d
>> classes.
>>
>> ```cpp
>> class Position : using std::pair<double, double> {};
>> class Distance : using std::pair<double, double> {};
>>
>> Position operator+(const Position & p, const Distance & d) {
>> return Position(p.first + d.first, p.second + d.second);
>> }
>>
>> Distance operator+(const Distance & lhs, const Distance & rhs) {
>> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
>> }
>>
>> // ...
>>
>> Position p(1, 1);
>> Distance d(1, 1);
>>
>> p + d; // OK
>> d + d; // OK
>> p + p; // Error
>> ```
>>
>> ### Templated Class Copy ###
>>
>> The user might want to create a single templatized copy interface, and
>> use it
>> multiple times. For example, one might want multiple copied classes whic=
h
>> can
>> convert to their original. This could be done as follows:
>>
>> ```cpp
>> struct A { int x; };
>>
>> template <typename T>
>> struct TemplatizedCopy : using T {
>> static_assert(std::is_standard_layout<T>::value,
>> "Can't use this with a non-standard-layout class");
>>
>> operator T&() { return *reinterpret_cast<T*>(this); }
>> };
>>
>> // Could be used either via normal typedefs
>> using Copy1 =3D TemplatizedCopy<A>;
>>
>> // Or via copy, depending on requirements.
>> struct Copy2 : using TemplatizedCopy<A> {};
>> ```
>>
>> ### Copying Template Classes ###
>>
>> Since the construct is similar to inheritance, the syntax for creating
>> aliases
>> of templated classes could be the same:
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T> {};
>>
>> B<int> b;
>> ```
>>
>> The copied class must have the same number or less of template parameter=
s
>> than
>> the base class. Partial or full specializations of the base class can be
>> allowed:
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> B<int> b;
>> ```
>>
>> When the base class has partial specializations, only those who apply ar=
e
>> copied
>> to the copied class.
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A { T t; U u; };
>>
>> template <typename U>
>> struct A<double, U> { double y; U u; };
>>
>> template <typename T>
>> struct A<T, int> { T t; char z; };
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> /* Equivalent to
>>
>> template <typename T>
>> struct B { T t; double u; };
>>
>> template <>
>> struct B<double> { double y; double u; };
>>
>> */
>> ```
>>
>> The copied class can add additional specializations. Or specializations
>> for a
>> given class can copy another.
>>
>> ```cpp
>> template <typename T>
>> struct A { int x; };
>>
>> struct B { char c; };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> template <>
>> struct C<double> : using B {};
>>
>> template <>
>> struct A<int> : using C<double> {};
>>
>> /* Equivalent to
>>
>> template<>
>> struct A<int> { char c; };
>>
>> template <typename T>
>> struct C { int x; };
>>
>> template <>
>> struct C<double> { char c; };
>>
>> */
>> ```
>>
>> ### Copying Multiple Dependent Classes ###
>>
>> Copying multiple classes using the simple syntax we have described can b=
e
>> impossible if those classes depend on one another. This is because each
>> copy
>> would depend on the originals, rather than on the copied classes. A
>> possible way
>> to specify such dependencies could be:
>>
>> ```cpp
>> struct A;
>>
>> struct B {
>> A * a;
>> };
>>
>> struct A {
>> B b;
>> };
>>
>> struct C;
>>
>> struct D : using B {
>> using class C =3D A;
>> };
>>
>> struct C : using A {
>> using class D =3D B;
>> };
>>
>> /* Equivalent to
>>
>> struct C;
>>
>> struct D {
>> C * a;
>> };
>>
>> struct C {
>> D b;
>> };
>>
>> */
>> ```
>>
>> `using class` has been used in order to disambiguate it from normal
>> `using`
>> alias directive. `using class` is only valid when the left hand side has
>> been
>> defined as a copy of the right hand side.
>>
>> In case of a template base class using a template second class, one coul=
d
>> specify different copies for certain specializations;
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B {
>> A<T> a;
>> };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> ```
>>
>> ### Substituting Existing Functionality (Optional) ###
>>
>> Ideally one may want to use most of an implementation for another class,
>> but
>> vary a certain number of methods. In this case, if `Copy` contains a
>> member
>> function that already exists in `Base`, then that implementation is
>> substituted
>> in `Copy`. This may or may not be allowed for attributes.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct Copy : using Base {
>> void foo() { std::cout << "baz\n"; }
>> };
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "baz\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> */
>> ```
>>
>> A side effect of this is that it could allow for some type of
>> "interface", where
>> some base class could be defined as:
>>
>> ```cpp
>> struct Base {
>> Base() =3D delete;
>> void foo();
>> void bar();
>> };
>>
>> struct Copy1 : using Base {
>> Copy1() =3D default;
>> void baz();
>> void foo() =3D delete;
>> };
>>
>> /* Equivalent to
>>
>> struct Copy1 {
>> Copy1() =3D default;
>> void bar();
>> void baz();
>> };
>>
>> */
>>
>> struct Copy2 : using Base {
>> Copy2(int);
>> void abc();
>> };
>>
>> /*
>>
>> Equivalent to
>>
>> struct Copy2 {
>> Copy2(int);
>> void foo();
>> void bar();
>> void abc();
>> };
>>
>> */
>> ```
>>
>> This feature could however present problems when the members changed als=
o
>> alter
>> behavior and/or variable types of non-modified member and non-member
>> functions,
>> since the new behavior could be either erroneous or ambiguous.
>>
>> ### Copying and Extending Primitive Types (Optional) ###
>>
>> The same syntax could be used in order to extend primitive types. Using
>> the
>> extension that allows the modification of the copied types, this could
>> allow for
>> creation of numeric types where some operations are disabled as needed.
>>
>> ```cpp
>> struct Id : using int {
>> Id operator+(Id, Id) =3D delete;
>> Id operator*(Id, Id) =3D delete;
>> // Non-explicitly deleted operators keep their validity
>>
>> // Defining new operators with the old type can allow interoperativi=
ty
>> Id operator+(Id, int);
>> // We can convert the copied type to the old one.
>> operator int() { return (*this) * 2; }
>> };
>>
>> /* Equivalent to
>>
>> class Id final {
>> public:
>> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
>> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>>
>> Id operator+(Id, int);
>> operator int() { return v_ * 2; }
>> private:
>> int v_;
>> };
>>
>> */
>> ```
>>
>> Note that when copying from a primitive types inheritance is forbidden a=
s
>> the
>> generated copy is `final` (although it is allowed to keep copying the
>> newly
>> created class).
>>
>> ### STL Traits (Optional) ###
>>
>> Traits could be included in the standard library in order to determine
>> whether a
>> class is a copy of another, or if it has been derived from a copy
>> (copies/inheritances could be nested arbitrarily).
>>
>> ```cpp
>> struct Base {};
>>
>> struct Copy : using Base {};
>>
>> static_assert(std::is_copy<Copy, Base>::value);
>>
>> struct ChildCopy : public Copy {};
>>
>> struct CopyChildCopy : using ChildCopy {};
>>
>> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
>> ```
>>
>> Compatibility
>> -------------
>>
>> As the syntax is new, no old code would be affected.
>>
>>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2BtuC%3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a%=
3DHudi74qSQ%40mail.gmail.com.
--001a114757521ae1c905452f024b
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Dear Vicente,<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"l=
tr"><div><div>Well, in inheritance child classes can be converted to
their parents automatically (even if they don't define a
constructor that initializes any new data they might have).
If that can be done I don't see why this would be impossibl=
e
for a copied class + a new non-static data member to do the
same thing.<br>
</div>
</div>
</div>
</blockquote></span>
You need to construct a derived from a base. If derived contains
more data you can not do it correctly.<br></blockquote><div><br></div><=
div>Well not necessarily. There are classes that take fewer parameters than=
the number of their members. There are classes that define a constructor w=
ith no parameters, even though they have members. There are structs with no=
constructor at all. <br><br></div><div>For example, if you copy a class an=
d add, say, an std::vector, I'd say it would be very easy to create the=
copy from the original, since the std::vector can initialize itself very e=
asily.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Yes. I was =
missing all the copies and I mixed base_type as the base
type of ConvertBack. Sorry for reading your code too quickly. <br>
<br>
I start liking your feature more and more. It could really help to
make easier to define opaque types. <br></blockquote><div><br></div><di=
v>I'm really glad you like it!<br><br><blockquote class=3D"gmail_quote"=
style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);p=
adding-left:1ex">Note how <br><span class=3D"gmail-im">
<br>
template <typename C><br>
struct Plus : using C {<br></span><span class=3D"gmail-im">
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus other) { return Plus{t_ + other.=
t_}; }<br>
};<br>
<br></span>
is close to=C2=A0 p0109<br>
<br>
template <typename C><br>
using Plus : private C {<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus x, Plus y) =3D default;<br>
};<span class=3D"gmail-im"><br></span></blockquote><div>=C2=A0<br></div=
><div>Yes. However, if non-member functions can be copied, I believe there =
should exist a syntax to create them also outside the copied class. Suppose=
:<br><br></div><div>// From library<br></div><div>struct A {};<br></div><di=
v>struct B : using A {}<br><br></div><div>// User defined<br></div><div>voi=
d foo(A a) {}<br></div><div>// How to define foo(B)?<br><br></div><div>The =
problem with this example is that when foo(A) is defined, B has already bee=
n defined. The original case in p0109 is "easy" in the sense that=
the non-member operators for primitive types are always defined before cop=
ies can be made, so they can surely be seen in the copy.<br><br></div><div>=
One could argue that such a problem does not exist, since the new function =
can be made template from the start and so apply to both A and B. Perhaps. =
I'm just asking the question out of completeness, I'm not sure what=
the answer should be.<br><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex"><span class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>If not, why not? Are you constrained in doing
this only in copied class and with functions
taking/returning the original class, maybe? Why?<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
No. You could substitute any type T by a type U if U(T(u)) =3D=3D u as
the trampoline is doing just this double conversion. The
particularity of opaque types is that the conversion costs nothing
as both classes share the same representation. For other types, the
cost of the conversions could be more visible.</blockquote><div><br></d=
iv><div>I'm not sure that definition always holds, unfortunately. You&#=
39;d have to force them to have the same public interface, or else maybe th=
e conversion from U->T->U will work, but T has a different interface =
so they are not compatible. Consider:<br><br></div><div>struct A {<br></div=
><div>=C2=A0=C2=A0=C2=A0 A() : x_(0) {}<br></div><div>=C2=A0=C2=A0=C2=A0 in=
t x_;<br></div><div>};<br><br></div><div>struct B {<br></div><div>=C2=A0=C2=
=A0=C2=A0 B(A a) : d_(5), i_(a.x_) {}<br></div><div>=C2=A0=C2=A0=C2=A0 oper=
ator A() { return A{i_}; } =C2=A0 <br></div><div>=C2=A0=C2=A0=C2=A0 <br>=C2=
=A0=C2=A0=C2=A0 double d_;<br></div><div>=C2=A0=C2=A0=C2=A0 int i_;<br></di=
v><div>};<br><br></div><div>double foo(B b) {<br></div><div>=C2=A0=C2=A0=C2=
=A0 return b.d_ + b.i_;<br></div><div>}<br><br></div><div>If you just follo=
w the conversion rules, then you could convert foo(B) into foo(A), since A(=
B(a)) =3D=3D a for any a. However, it would fail to compile as of course B =
and A do not have the same interface. You'd have to guarantee that when=
converting A to B that A has at least the same interface as B (which is th=
e same as copying, pretty much, even though it does not require it since on=
e could do this by hand). This includes static members, typedefs, etc etc. =
It would also include non-member functions possibly - if foo uses them.<br>=
<br></div><div>The only way to practically make that check would be to just=
let the compiler try, probably. Which would be equivalent to transforming =
foo into a templated function. Which I'm not sure is going to get accep=
ted.<br></div><div><br></div><div>Best,<br></div><div>Eugenio<br></div></di=
v></div></div></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quot=
e">On Tue, Jan 3, 2017 at 8:52 AM, <span dir=3D"ltr"><<a href=3D"mailto=
:iontodirel@gmail.com" target=3D"_blank">iontodirel@gmail.com</a>></span=
> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">What about a sy=
ntax like this:<br><br>struct Foo<br>{<div>};<br>typealias int int_;<div>ty=
pealias Foo Foo2;<div><div class=3D"h5"><br><br>On Monday, December 19, 201=
6 at 3:04:48 AM UTC-8, <a href=3D"mailto:sval...@gmail.com" target=3D"_blan=
k">sval...@gmail.com</a> wrote:<blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
dir=3D"ltr">This is a stub proposal on strong typedefs, i.e. types that wo=
rk in the exact same way, but allow separate overloading. Other papers and =
proposals exist, but I've tried a different approach that tries to mimi=
c a more inheritance-like syntax which might be more intuitive. The full te=
xt can be found online at <a href=3D"https://github.com/Svalorzen/CppCopyPr=
oposal" rel=3D"nofollow" target=3D"_blank">https://github.com/Svalorzen/C<w=
br>ppCopyProposal.<br><br></a>I'm copying the text below. Thanks in adv=
ance for your comments.<br><br><span style=3D"font-family:courier new,monos=
pace">Duplication and Extension of Existing Classes<br>=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<wb=
r>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>Introduction<br>----=
--------<br><br>This document describes a possible approach to duplicate ex=
isting functionality<br>while wrapping it in a new type, without the burden=
of inheritance and to allow<br>function overloads on syntactically identic=
al but semantically different types<br>(also known as *strong typedef*).<br=
><br>The approach taken should be simple to implement and be applicable to =
existing<br>code.<br><br>Optional sections are to be read as additional ide=
as that could be further<br>developed or completely ignored. They are mostl=
y food for thought, but included<br>for completeness.<br><br>Reasons<br>---=
----<br><br>- Scientific libraries where a type has different behaviors dep=
ending on context<br>=C2=A0 have currently no simple way to indicate the se=
mantic differences. Since a<br>=C2=A0 `typedef` does not allow multiple ove=
rloads on new typedef types - since they<br>=C2=A0 are still the "old&=
quot; type - they have to resort to imperfect techniques, such<br>=C2=A0 as=
copying, wrapping or inheriting the needed type. Examples: coordinates in =
a<br>=C2=A0 plane (rectangular, polar), vectors of double (probabilities, v=
alues).<br>- Easier maintainability of code which is known to be the same, =
rather than<br>=C2=A0 being copy-pasted.<br>- Avoiding misuse of inheritanc=
e in order to provide a copy-paste alternative.<br>=C2=A0 This can result i=
n very deep hierarchies of types which should really not have<br>=C2=A0 any=
thing to do with each other.<br>- Enabling users to use an existing and pre=
sumably correct type but partially<br>=C2=A0 extend it with context-specifi=
c methods. Examples: search for "`std::vector`<br>=C2=A0 inheritance&q=
uot; yields many results of users trying to maintain the original<br>=C2=A0=
interface and functionality but add one or two methods.<br><br>The functio=
nality should have the following requirements:<br><br>- Can be applied to e=
xisting code.<br>- Should limit dependencies between new and old type as mu=
ch as possible.<br>- Should allow for partial extensions of the old code.<b=
r><br>Alternatives<br>------------<br><br>### Typedef / Using Directive ###=
<br><br>Using a type alias creates an alternative name for a single type. H=
owever, this<br>leaves no space to implement overloads that are context-spe=
cific. Nor a type can<br>be extended in a simple way while keeping the old =
interface intact.<br><br>### Inheritance ###<br><br>Inheritance requires re=
definition of all constructors, and creates a stricter<br>dependency betwee=
n two classes than what is proposed here. Classes may be<br>converted to a =
common ancestor even though that is undesired or even dangerous<br>in case =
of implicit conversions.<br><br>Inheritance may also be unwanted in order t=
o avoid risks linked to polymorphism<br>and freeing data structures where t=
he base class does not have a virtual<br>destructor.<br><br>### Encapsulati=
on with Manual Exposure of Needed Methods ###<br><br>This method obviously =
requires a great deal of code to be rewritten in order to<br>wrap every sin=
gle method that the old class was exposing.<br><br>In addition one needs to=
have intimate knowledge of the original interface in<br>order to be able t=
o duplicate it correctly. Template methods, rvalue references,<br>possibly =
undocumented methods which are required in order to allow the class to<br>b=
ehave in the same way as before. This heightens the bar significantly for m=
any<br>users, since they may not know correctly how to duplicate an interfa=
ce and how<br>to forward parameters to the old interface correctly.<br><br>=
The new code also must be maintained in case the old interface changes.<br>=
<br>### Copying the Base Class ###<br><br>This can be useful, but requires =
all code to be duplicated, and thus<br>significantly increases the burden o=
f maintaining the code. All bugs discovered<br>in one class must be fixed i=
n the other class too. All new features applied to<br>one class must be app=
lied to the other too.<br><br>### Macro-expansion ###<br><br>Macro expansio=
ns can be used in order to encode the interface and implementation<br>of a =
given class just one time, and used multiple times to produce separate<br>c=
lasses.<br><br>This approach is unfortunately not applicable to existing co=
de, and is very hard<br>to extend if one wants to copy a class but add addi=
tional functionality to it.<br><br>### Templates ###<br><br>Templates produ=
ce for each instantiation a separate type. They are unfortunately<br>not ap=
plicable to previously existing code. For new code, they would require the<=
br>creation of "fake" template parameters that would need to vary=
in order to<br>produce separate types.<br><br>In addition, class extension=
through templates is not possible: variations would<br>need to be made thr=
ough specialization, which itself requires copying existing<br>code.<br><br=
>Previous Work<br>-------------<br><br>Strong typedefs have already been pr=
oposed for the C++ language multiple times<br>([N1706](<a href=3D"http://ww=
w.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf" rel=3D"nofollow" =
target=3D"_blank">http://www.open-std.o<wbr>rg/jtc1/sc22/wg21/docs/papers/<=
wbr>2004/n1706.pdf</a>),<br>[N1891](<a href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2005/n1891.pdf" rel=3D"nofollow" target=3D"_blank">h=
ttp://www.open-std.or<wbr>g/jtc1/sc22/wg21/docs/papers/<wbr>2005/n1891.pdf<=
/a>),<br>[N3515](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/pap=
ers/2013/n3515.pdf" rel=3D"nofollow" target=3D"_blank">http://www.open-std.=
or<wbr>g/jtc1/sc22/wg21/docs/papers/<wbr>2013/n3515.pdf</a>),<br>[N3741](<a=
href=3D"https://isocpp.org/files/papers/n3741.pdf)" rel=3D"nofollow" targe=
t=3D"_blank">https://isocpp.org/fil<wbr>es/papers/n3741.pdf)</a>). These ty=
pedefs are named<br>*opaque typedefs*, and these papers try to explore and =
define exactly the<br>behavior that such typedefs should and would have whe=
n used to create new<br>types. In particular, the keywords `public`, `prote=
cted` and `private` are used<br>in order to create a specific relation with=
the original type and how is the<br>new type allowed to be cast back to th=
e original type or be used in its place<br>during overloads.<br><br>This do=
cument shares many of the the same principles, for example (quoting from<br=
>N3741):<br><br>> - Consistent with restrictions imposed on analogous re=
lationships such as<br>>=C2=A0=C2=A0 base classes underlying derived cla=
sses and integer types underlying enums,<br>>=C2=A0=C2=A0 an underlying =
type should be (1) complete and (2) not cv-quali=EF=AC=81ed. We also do<br>=
>=C2=A0=C2=A0 not require that any enum type, reference type, array type=
, function type, or<br>>=C2=A0=C2=A0 pointer-to-member type be allowed a=
s an underlying type.<br><br>However, this document tries to propose a poss=
ibly more simple approach, where<br>a new language feature is introduced wi=
th the same meaning and functionality as<br>if the user autonomously implem=
ented a new class him/herself, matching the<br>original type completely. Th=
us, it should result for the user more simple to<br>understand (as it simpl=
y matches already the already understood mechanics of<br>creating a new, un=
ique type from nothing), and no new rules for type conversion<br>and select=
ion on overloads have to be created.<br><br>Syntax<br>------<br><br>### Sim=
ple Case ###<br><br>Syntax could look something like this:<br><br>```cpp<br=
>class Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0 Base() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 void foo() { std::cout << "foo " << x << &q=
uot;\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>struct Copy : using Base {};<br><br>=
/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo "=
; << x << "\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br=
><br>One cannot copy a class and inherit at the same time. If such a class =
is needed<br>one would need to create it by hand with the desided functiona=
lity and<br>inheriting from the desired classes, as it would be done normal=
ly.<br><br>All method implementations would be the same. The copied class w=
ould inherit<br>from the same classes its base class inherits from. All con=
structors would work<br>in the same way.<br><br>### Adding New Functionalit=
y ###<br><br>Ideally one could specify additional methods, separate from th=
at of Base, to add<br>upon the existing functionality.<br><br>```cpp<br>str=
uct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\=
n"; }<br>};<br><br>struct Derived : public Base {};<br><br>struct Copy=
: using Base {<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "=
;bar\n"; }<br>};<br><br>struct CopyDerived : using Derived {};<br><br>=
/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { st=
d::cout << "foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { st=
d::cout << "bar\n"; }<br>};<br><br>struct CopyDerived : pub=
lic Base {};<br><br>*/<br>```<br><br>Only new methods need to be implemente=
d for that class.<br><br>#### Interfacing with the Original Class ####<br><=
br>In order to interface with the original class, simple conversion operato=
rs can<br>be added by the user explicitly at-will, in order to obtain the d=
esired<br>interface. Note that if more types with this kind of compatibilit=
y were needed,<br>one would only need to implement them once, since copying=
the produced type<br>would copy the new, more compatible interface with it=
..<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:=
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struc=
t Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x=
, y}; }<br>};<br>```<br><br>`reinterpret_cast` may also be used to convert =
back to the original class,<br>limited by the tool's already existing r=
ules.<br><br>In general the usual rules of `reinterpret_cast` apply to the =
copied classes<br>with respect to their general classes, exactly as if the =
copied class had been<br>implemented by hand.<br><br>### Overloads ###<br><=
br>Duplicating an existing class should allow for new overloads on the new =
type,<br>and no ambiguity between the copied class, the old class and other=
copied<br>classes.<br><br>```cpp<br>class Position : using std::pair<do=
uble, double> {};<br>class Distance : using std::pair<double, double&=
gt; {};<br><br>Position operator+(const Position & p, const Distance &a=
mp; d) {<br>=C2=A0=C2=A0=C2=A0 return Position(p.first + d.first, p.second =
+ d.second);<br>}<br><br>Distance operator+(const Distance & lhs, const=
Distance & rhs) {<br>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rh=
s.first, lhs.second + rhs.second);<br>}<br><br>// ...<br><br>Position p(1, =
1);<br>Distance d(1, 1);<br><br>p + d; // OK<br>d + d; // OK<br>p + p; // E=
rror<br>```<br><br>### Templated Class Copy ###<br><br>The user might want =
to create a single templatized copy interface, and use it<br>multiple times=
.. For example, one might want multiple copied classes which can<br>convert =
to their original. This could be done as follows:<br><br>```cpp<br>struct A=
{ int x; };<br><br>template <typename T><br>struct TemplatizedCopy :=
using T {<br>=C2=A0=C2=A0=C2=A0 static_assert(std::is_standard<wbr>_layout=
<T>::value,<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this w=
ith a non-standard-layout class");<br><br>=C2=A0=C2=A0=C2=A0 operator =
T&() { return *reinterpret_cast<T*>(this); }<br>};<br><br>// Coul=
d be used either via normal typedefs<br>using Copy1 =3D TemplatizedCopy<=
A>;<br><br>// Or via copy, depending on requirements.<br>struct Copy2 : =
using TemplatizedCopy<A> {};<br>```<br><br>### Copying Template Class=
es ###<br><br>Since the construct is similar to inheritance, the syntax for=
creating aliases<br>of templated classes could be the same:<br><br>```cpp<=
br>template <typename T><br>struct A {};<br><br>template <typename=
T><br>struct B : using A<T> {};<br><br>B<int> b;<br>```<br>=
<br>The copied class must have the same number or less of template paramete=
rs than<br>the base class. Partial or full specializations of the base clas=
s can be allowed:<br><br>```cpp<br>template <typename T, typename U><=
br>struct A {};<br><br>template <typename T><br>struct B : using A<=
;T, double> {};<br><br>B<int> b;<br>```<br><br>When the base class=
has partial specializations, only those who apply are copied<br>to the cop=
ied class.<br><br>```cpp<br>template <typename T, typename U><br>stru=
ct A { T t; U u; };<br><br>template <typename U><br>struct A<doubl=
e, U> { double y; U u; };<br><br>template <typename T><br>struct A=
<T, int> { T t; char z; };<br><br>template <typename T><br>stru=
ct B : using A<T, double> {};<br><br>/* Equivalent to<br><br>template=
<typename T><br>struct B { T t; double u; };<br><br>template <>=
;<br>struct B<double> { double y; double u; };<br><br>*/<br>```<br><b=
r>The copied class can add additional specializations. Or specializations f=
or a<br>given class can copy another.<br><br>```cpp<br>template <typenam=
e T><br>struct A { int x; };<br><br>struct B { char c; };<br><br>templat=
e <typename T><br>struct C : using A<T> {};<br><br>template <=
;><br>struct C<double> : using B {};<br><br>template <><br>s=
truct A<int> : using C<double> {};<br><br>/* Equivalent to<br><=
br>template<><br>struct A<int> { char c; };<br><br>template <=
;typename T><br>struct C { int x; };<br><br>template <><br>struct =
C<double> { char c; };<br><br>*/<br>```<br><br>### Copying Multiple D=
ependent Classes ###<br><br>Copying multiple classes using the simple synta=
x we have described can be<br>impossible if those classes depend on one ano=
ther. This is because each copy<br>would depend on the originals, rather th=
an on the copied classes. A possible way<br>to specify such dependencies co=
uld be:<br><br>```cpp<br>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 =
A * a;<br>};<br><br>struct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>stru=
ct C;<br><br>struct D : using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A=
;<br>};<br><br>struct C : using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D=
B;<br>};<br><br>/* Equivalent to<br><br>struct C;<br><br>struct D {<br>=C2=
=A0=C2=A0=C2=A0 C * a;<br>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<b=
r>};<br><br>*/<br>```<br><br>`using class` has been used in order to disamb=
iguate it from normal `using`<br>alias directive. `using class` is only val=
id when the left hand side has been<br>defined as a copy of the right hand =
side.<br><br>In case of a template base class using a template second class=
, one could<br>specify different copies for certain specializations;<br><br=
>```cpp<br>template <typename T><br>struct A {};<br><br>template <=
typename T><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><=
br>template <typename T><br>struct C : using A<T> {};<br><br>``=
`<br><br>### Substituting Existing Functionality (Optional) ###<br><br>Idea=
lly one may want to use most of an implementation for another class, but<br=
>vary a certain number of methods. In this case, if `Copy` contains a membe=
r<br>function that already exists in `Base`, then that implementation is su=
bstituted<br>in `Copy`. This may or may not be allowed for attributes.<br><=
br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout <=
;< "foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout <=
;< "bar\n"; }<br>};<br><br>struct Copy : using Base {<br>=C2=
=A0=C2=A0=C2=A0 void foo() { std::cout << "baz\n"; }<br>};<=
br><br>/* Equivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo=
() { std::cout << "baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar=
() { std::cout << "bar\n"; }<br>};<br><br>*/<br>```<br><br>=
A side effect of this is that it could allow for some type of "interfa=
ce", where<br>some base class could be defined as:<br><br>```cpp<br>st=
ruct Base {<br>=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 =
void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : u=
sing Base {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=
=A0 void baz();<br>=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/=
* Equivalent to<br><br>struct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D def=
ault;<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<b=
r>};<br><br>*/<br><br>struct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Cop=
y2(int);<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalen=
t to<br><br>struct Copy2 {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=
=A0=C2=A0 void foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=
=A0 void abc();<br>};<br><br>*/<br>```<br><br>This feature could however pr=
esent problems when the members changed also alter<br>behavior and/or varia=
ble types of non-modified member and non-member functions,<br>since the new=
behavior could be either erroneous or ambiguous.<br><br>### Copying and Ex=
tending Primitive Types (Optional) ###<br><br>The same syntax could be used=
in order to extend primitive types. Using the<br>extension that allows the=
modification of the copied types, this could allow for<br>creation of nume=
ric types where some operations are disabled as needed.<br><br>```cpp<br>st=
ruct Id : using int {<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete=
;<br>=C2=A0=C2=A0=C2=A0 Id operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=
=A0 // Non-explicitly deleted operators keep their validity<br><br>=C2=A0=
=C2=A0=C2=A0 // Defining new operators with the old type can allow interope=
rativity<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=
// We can convert the copied type to the old one.<br>=C2=A0=C2=A0=C2=A0 op=
erator int() { return (*this) * 2; }<br>};<br><br>/* Equivalent to<br><br>c=
lass Id final {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_=
}; }<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id =
rhs) { return Id{lhs.v_ - rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 operator int() { return v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<b=
r><br>Note that when copying from a primitive types inheritance is forbidde=
n as the<br>generated copy is `final` (although it is allowed to keep copyi=
ng the newly<br>created class).<br><br>### STL Traits (Optional) ###<br><br=
>Traits could be included in the standard library in order to determine whe=
ther a<br>class is a copy of another, or if it has been derived from a copy=
<br>(copies/inheritances could be nested arbitrarily).<br><br>```cpp<br>str=
uct Base {};<br><br>struct Copy : using Base {};<br><br>static_assert(std::=
is_copy<Cop<wbr>y, Base>::value);<br><br>struct ChildCopy : public Co=
py {};<br><br>struct CopyChildCopy : using ChildCopy {};<br><br>static_asse=
rt(std::is_copy_bas<wbr>e_of<Base, CopyChildCopy>::value);<br>```<br>=
<br>Compatibility<br>-------------<br><br>As the syntax is new, no old code=
would be affected.<br></span><br></div></blockquote></div></div></div></di=
v></div></blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BtuC%3Dd671Z-vRT82QoSKNz-Wq=
3sw4eToa9a%3DHudi74qSQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoo=
ter">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%=
2BtuC%3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a%3DHudi74qSQ%40mail.gmail.com</a>.<br=
/>
--001a114757521ae1c905452f024b--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Tue, 3 Jan 2017 18:29:18 +0100
Raw View
This is a multi-part message in MIME format.
--------------1F6CEE7EFB948BDAD8ADD49A
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 03/01/2017 =C3=A0 12:31, Eugenio Bargiacchi a =C3=A9crit :
> Dear Vicente,
>
>> Well, in inheritance child classes can be converted to their
>> parents automatically (even if they don't define a constructor
>> that initializes any new data they might have). If that can be
>> done I don't see why this would be impossible for a copied class
>> + a new non-static data member to do the same thing.
> You need to construct a derived from a base. If derived contains
> more data you can not do it correctly.
>
>
> Well not necessarily. There are classes that take fewer parameters=20
> than the number of their members. There are classes that define a=20
> constructor with no parameters, even though they have members. There=20
> are structs with no constructor at all.
>
> For example, if you copy a class and add, say, an std::vector, I'd say=20
> it would be very easy to create the copy from the original, since the=20
> std::vector can initialize itself very easily.
>
> Yes. I was missing all the copies and I mixed base_type as the
> base type of ConvertBack. Sorry for reading your code too quickly.
>
> I start liking your feature more and more. It could really help to
> make easier to define opaque types.
>
>
> I'm really glad you like it!
>
> Note how
>
> template <typename C>
> struct Plus : using C {
> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
> };
>
> is close to p0109
>
> template <typename C>
> using Plus : private C {
> Plus operator+(Plus x, Plus y) =3D default;
> };
>
>
> Yes. However, if non-member functions can be copied, I believe there=20
> should exist a syntax to create them also outside the copied class.=20
> Suppose:
>
> // From library
> struct A {};
> struct B : using A {}
>
> // User defined
> void foo(A a) {}
> // How to define foo(B)?
>
> The problem with this example is that when foo(A) is defined, B has=20
> already been defined. The original case in p0109 is "easy" in the=20
> sense that the non-member operators for primitive types are always=20
> defined before copies can be made, so they can surely be seen in the copy=
..
p0109 manages with classes as underling types also.
>
> One could argue that such a problem does not exist, since the new=20
> function can be made template from the start and so apply to both A=20
> and B. Perhaps. I'm just asking the question out of completeness, I'm=20
> not sure what the answer should be.
If B is copied later the following could be a possibility
struct B : using A {
friend void foo(B b) =3D default;
};
Otherwise the user can do just:
void foo(B b) { foo(A(b)); };
I don't know if it is worth providing something else to take care of=20
this function copy.
Maybe
void foo(B b) =3D default;
>
>> If not, why not? Are you constrained in doing this only in copied
>> class and with functions taking/returning the original class,
>> maybe? Why?
> No. You could substitute any type T by a type U if U(T(u)) =3D=3D u a=
s
> the trampoline is doing just this double conversion. The
> particularity of opaque types is that the conversion costs nothing
> as both classes share the same representation. For other types,
> the cost of the conversions could be more visible.
>
>
> I'm not sure that definition always holds, unfortunately. You'd have=20
> to force them to have the same public interface, or else maybe the=20
> conversion from U->T->U will work, but T has a different interface so=20
> they are not compatible. Consider:
>
> struct A {
> A() : x_(0) {}
> int x_;
> };
>
> struct B {
> B(A a) : d_(5), i_(a.x_) {}
> operator A() { return A{i_}; }
>
> double d_;
> int i_;
> };
>
> double foo(B b) {
> return b.d_ + b.i_;
> }
>
> If you just follow the conversion rules, then you could convert foo(B)=20
> into foo(A), since A(B(a)) =3D=3D a for any a.
Right.
> However, it would fail to compile as of course B and A do not have the=20
> same interface. You'd have to guarantee that when converting A to B=20
> that A has at least the same interface as B (which is the same as=20
> copying, pretty much, even though it does not require it since one=20
> could do this by hand). This includes static members, typedefs, etc=20
> etc. It would also include non-member functions possibly - if foo uses=20
> them.
>
You lost me. My copy is not the same as yours. I don't copy the function=20
code, as I don't have access to it. It is not a template at all. The=20
copied function is wrapping the existing functions.
double foo(A a) {
return foo(B(a);
}
When one type is the opaque type of the other the conversion is trivial=20
and so there is no need of trampoline in realiyt. Only the compiler must=20
check the types and call to the base function.
> The only way to practically make that check would be to just let the=20
> compiler try, probably. Which would be equivalent to transforming foo=20
> into a templated function. Which I'm not sure is going to get accepted.
>
>
Vicente
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/44d44d44-483e-1ee5-90a7-1a4b966858f5%40wanadoo.f=
r.
--------------1F6CEE7EFB948BDAD8ADD49A
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 03/01/2017 =C3=A0 12:31, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">Dear Vicente,<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><s=
pan
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>Well, in inheritance child classes can be
converted to their parents automatically (even if
they don't define a constructor that initializes any
new data they might have). If that can be done I
don't see why this would be impossible for a copied
class + a new non-static data member to do the same
thing.<br>
</div>
</div>
</div>
</blockquote>
</span> You need to construct a derived from a base. If
derived contains more data you can not do it correctly.<br>
</blockquote>
<div><br>
</div>
<div>Well not necessarily. There are classes that take fewer
parameters than the number of their members. There are classes
that define a constructor with no parameters, even though they
have members. There are structs with no constructor at all. <br>
<br>
</div>
<div>For example, if you copy a class and add, say, an
std::vector, I'd say it would be very easy to create the copy
from the original, since the std::vector can initialize itself
very easily.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Yes. I was missing all
the copies and I mixed base_type as the base type of
ConvertBack. Sorry for reading your code too quickly. <br>
<br>
I start liking your feature more and more. It could really
help to make easier to define opaque types. <br>
</blockquote>
<div><br>
</div>
<div>I'm really glad you like it!<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">Note how <br>
<span class=3D"gmail-im"> <br>
template <typename C><br>
struct Plus : using C {<br>
</span><span class=3D"gmail-im"> =C2=A0=C2=A0=C2=A0 Plus oper=
ator+(Plus
other) { return Plus{t_ + other.t_}; }<br>
};<br>
<br>
</span> is close to=C2=A0 p0109<br>
<br>
template <typename C><br>
using Plus : private C {<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus x, Plus y) =3D default=
;<br>
};<span class=3D"gmail-im"><br>
</span></blockquote>
<div>=C2=A0<br>
</div>
<div>Yes. However, if non-member functions can be copied, I
believe there should exist a syntax to create them also
outside the copied class. Suppose:<br>
<br>
</div>
<div>// From library<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {}<br>
<br>
</div>
<div>// User defined<br>
</div>
<div>void foo(A a) {}<br>
</div>
<div>// How to define foo(B)?<br>
<br>
</div>
<div>The problem with this example is that when foo(A) is
defined, B has already been defined. The original case in
p0109 is "easy" in the sense that the non-member operators
for primitive types are always defined before copies can
be made, so they can surely be seen in the copy.<br>
</div>
</div>
</div>
</div>
</blockquote>
<br>
p0109 manages with classes as underling types also.<br>
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>One could argue that such a problem does not exist,
since the new function can be made template from the start
and so apply to both A and B. Perhaps. I'm just asking the
question out of completeness, I'm not sure what the answer
should be.<br>
</div>
</div>
</div>
</div>
</blockquote>
If B is copied later the following could be a possibility<br>
<br>
struct B : using A {<br>
=C2=A0=C2=A0=C2=A0 friend void foo(B b) =3D default;<br>
};<br>
<br>
Otherwise the user can do just:<br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b)=C2=A0 { foo(A(b)); };<br>
<br>
I don't know if it is worth providing something else to take care of
this function copy.<br>
Maybe <br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b) =3D default;<br>
<br>
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span
class=3D"gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>If not, why not? Are you
constrained in doing this only in
copied class and with functions
taking/returning the original class,
maybe? Why?<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> No. You could substitute any type T by a type U
if U(T(u)) =3D=3D u as the trampoline is doing just this
double conversion. The particularity of opaque types is
that the conversion costs nothing as both classes share
the same representation. For other types, the cost of
the conversions could be more visible.</blockquote>
<div><br>
</div>
<div>I'm not sure that definition always holds,
unfortunately. You'd have to force them to have the same
public interface, or else maybe the conversion from
U->T->U will work, but T has a different interface
so they are not compatible. Consider:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 A() : x_(0) {}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int x_;<br>
</div>
<div>};<br>
<br>
</div>
<div>struct B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 B(A a) : d_(5), i_(a.x_) {}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() { return A{i_}; } =C2=A0=
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 <br>
=C2=A0=C2=A0=C2=A0 double d_;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int i_;<br>
</div>
<div>};<br>
<br>
</div>
<div>double foo(B b) {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 return b.d_ + b.i_;<br>
</div>
<div>}<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<br>
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>If you just follow the conversion rules, then you
could convert foo(B) into foo(A), since A(B(a)) =3D=3D a fo=
r
any a.</div>
</div>
</div>
</div>
</div>
</blockquote>
Right.
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div> However, it would fail to compile as of course B and
A do not have the same interface. You'd have to
guarantee that when converting A to B that A has at
least the same interface as B (which is the same as
copying, pretty much, even though it does not require it
since one could do this by hand). This includes static
members, typedefs, etc etc. It would also include
non-member functions possibly - if foo uses them.<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
You lost me. My copy is not the same as yours. I don't copy the
function code, as I don't have access to it. It is not a template at
all. The copied function is wrapping the existing functions.<br>
<br>
<div>double foo(A a) {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 return foo(B(a);<br>
</div>
}<br>
<br>
When one type is the opaque type of the other the conversion is
trivial and so there is no need of trampoline in realiyt. Only the
compiler must check the types and call to the base function.<br>
<br>
<blockquote
cite=3D"mid:CAHfn=3D+tuC=3Dd671Z-vRT82QoSKNz-Wq3sw4eToa9a=3DHudi74qSQ@mail.=
gmail.com"
type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The only way to practically make that check would be
to just let the compiler try, probably. Which would be
equivalent to transforming foo into a templated
function. Which I'm not sure is going to get accepted.<br>
</div>
<div><br>
</div>
<br>
</div>
</div>
</div>
</div>
</blockquote>
Vicente<br>
<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/44d44d44-483e-1ee5-90a7-1a4b966858f5%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/44d44d44-483e-1ee5-90a7-1a4b966858f5=
%40wanadoo.fr</a>.<br />
--------------1F6CEE7EFB948BDAD8ADD49A--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Tue, 3 Jan 2017 19:21:33 +0100
Raw View
--94eb2c041276f359e8054534bca1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Dear Vicente,
The problem with this example is that when foo(A) is defined, B has already
> been defined. The original case in p0109 is "easy" in the sense that the
> non-member operators for primitive types are always defined before copies
> can be made, so they can surely be seen in the copy.
>
> p0109 manages with classes as underling types also.
>
Yes, of course. I meant the energy example.
One could argue that such a problem does not exist, since the new function
> can be made template from the start and so apply to both A and B. Perhaps=
..
> I'm just asking the question out of completeness, I'm not sure what the
> answer should be.
>
> If B is copied later the following could be a possibility
>
> struct B : using A {
> friend void foo(B b) =3D default;
> };
>
This I like, although it does not really need to be a friend, does it?
Otherwise the user can do just:
>
> void foo(B b) { foo(A(b)); };
This won't do, as we don't necessarily want B to be convertible to A. There
should be something like copy_cast<A>(b), but I don't like it.
Maybe
>
> void foo(B b) =3D default;
>
This could work but it has the potential to be unclear, as this definition
could happen far away from B so it has less context. Maybe just restricting
us to the case where all needed non-member functions have already been
declared is still enough. I would do that for the moment.
You lost me. My copy is not the same as yours. I don't copy the function
> code, as I don't have access to it. It is not a template at all. The copi=
ed
> function is wrapping the existing functions.
>
> double foo(A a) {
> return foo(B(a);
> }
If A is convertible to B, you don't need a new way to declare a trampoline
at all. The lines you wrote are enough (and I think also short enough), no
new syntax needs to be introduced. It wouldn't matter if A is a copy of B
or not.
If A is not directly convertible to B, what I said stands.
If you want to assume that B and A have the same underlying representation,
you could try casting them bit by bit. But this would be equivalent to
double foo(A a) {
return foo(*reinterpret_cast<B*>(a));
}
which is undefined behaviour in 90% of cases, even if the two classes are
literally identical (as they must be standard_layout for it to be valid in
C++, for some reason). So this is not going to work either. As in:
struct A {
int a;
private:
int b;
};
struct B {
int a;
private:
int b;
};
A a;
auto b =3D *reinterpret_cast<B*>(a); // undefined behaviour
This is undefined behaviour by the current standard. This proposal (and
assume also p0109) rests on the assumption that this undefined behaviour
can be relaxed when we explicitly define a class to be a copy of another.
Otherwise you'd have to first try a proposal to change how reinterpret_cast
work. However, as it's behaviour is different from C, I assume it has been
deliberately modified for some reason (which I don't know), so it probably
won't be simple.
Best,
Eugenio
On Tue, Jan 3, 2017 at 6:29 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Le 03/01/2017 =C3=A0 12:31, Eugenio Bargiacchi a =C3=A9crit :
>
> Dear Vicente,
>
>> Well, in inheritance child classes can be converted to their parents
>> automatically (even if they don't define a constructor that initializes =
any
>> new data they might have). If that can be done I don't see why this woul=
d
>> be impossible for a copied class + a new non-static data member to do th=
e
>> same thing.
>>
>> You need to construct a derived from a base. If derived contains more
>> data you can not do it correctly.
>>
>
> Well not necessarily. There are classes that take fewer parameters than
> the number of their members. There are classes that define a constructor
> with no parameters, even though they have members. There are structs with
> no constructor at all.
>
> For example, if you copy a class and add, say, an std::vector, I'd say it
> would be very easy to create the copy from the original, since the
> std::vector can initialize itself very easily.
>
> Yes. I was missing all the copies and I mixed base_type as the base type
>> of ConvertBack. Sorry for reading your code too quickly.
>>
>> I start liking your feature more and more. It could really help to make
>> easier to define opaque types.
>>
>
> I'm really glad you like it!
>
> Note how
>>
>> template <typename C>
>> struct Plus : using C {
>> Plus operator+(Plus other) { return Plus{t_ + other.t_}; }
>> };
>>
>> is close to p0109
>>
>> template <typename C>
>> using Plus : private C {
>> Plus operator+(Plus x, Plus y) =3D default;
>> };
>>
>
> Yes. However, if non-member functions can be copied, I believe there
> should exist a syntax to create them also outside the copied class. Suppo=
se:
>
> // From library
> struct A {};
> struct B : using A {}
>
> // User defined
> void foo(A a) {}
> // How to define foo(B)?
>
> The problem with this example is that when foo(A) is defined, B has
> already been defined. The original case in p0109 is "easy" in the sense
> that the non-member operators for primitive types are always defined befo=
re
> copies can be made, so they can surely be seen in the copy.
>
>
> p0109 manages with classes as underling types also.
>
>
> One could argue that such a problem does not exist, since the new functio=
n
> can be made template from the start and so apply to both A and B. Perhaps=
..
> I'm just asking the question out of completeness, I'm not sure what the
> answer should be.
>
> If B is copied later the following could be a possibility
>
> struct B : using A {
> friend void foo(B b) =3D default;
> };
>
> Otherwise the user can do just:
>
> void foo(B b) { foo(A(b)); };
>
> I don't know if it is worth providing something else to take care of this
> function copy.
> Maybe
>
> void foo(B b) =3D default;
>
>
> If not, why not? Are you constrained in doing this only in copied class
>> and with functions taking/returning the original class, maybe? Why?
>>
>> No. You could substitute any type T by a type U if U(T(u)) =3D=3D u as t=
he
>> trampoline is doing just this double conversion. The particularity of
>> opaque types is that the conversion costs nothing as both classes share =
the
>> same representation. For other types, the cost of the conversions could =
be
>> more visible.
>
>
> I'm not sure that definition always holds, unfortunately. You'd have to
> force them to have the same public interface, or else maybe the conversio=
n
> from U->T->U will work, but T has a different interface so they are not
> compatible. Consider:
>
> struct A {
> A() : x_(0) {}
> int x_;
> };
>
> struct B {
> B(A a) : d_(5), i_(a.x_) {}
> operator A() { return A{i_}; }
>
> double d_;
> int i_;
> };
>
> double foo(B b) {
> return b.d_ + b.i_;
> }
>
>
> If you just follow the conversion rules, then you could convert foo(B)
> into foo(A), since A(B(a)) =3D=3D a for any a.
>
> Right.
>
> However, it would fail to compile as of course B and A do not have the
> same interface. You'd have to guarantee that when converting A to B that =
A
> has at least the same interface as B (which is the same as copying, prett=
y
> much, even though it does not require it since one could do this by hand)=
..
> This includes static members, typedefs, etc etc. It would also include
> non-member functions possibly - if foo uses them.
>
> You lost me. My copy is not the same as yours. I don't copy the function
> code, as I don't have access to it. It is not a template at all. The copi=
ed
> function is wrapping the existing functions.
>
> double foo(A a) {
> return foo(B(a);
> }
>
> When one type is the opaque type of the other the conversion is trivial
> and so there is no need of trampoline in realiyt. Only the compiler must
> check the types and call to the base function.
>
> The only way to practically make that check would be to just let the
> compiler try, probably. Which would be equivalent to transforming foo int=
o
> a templated function. Which I'm not sure is going to get accepted.
>
>
> Vicente
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/44d44d44-483e-1ee5-
> 90a7-1a4b966858f5%40wanadoo.fr
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/44d44d44-48=
3e-1ee5-90a7-1a4b966858f5%40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAHfn%3D%2Bt59Uu0u6F6GJue7yaJOgffLh_7WpoKC%2Bfky=
32oGfhK0Q%40mail.gmail.com.
--94eb2c041276f359e8054534bca1
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Dear Vicente,<br><br><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex"><div>The problem with this example is that when foo(A) is
defined, B has already been defined. The original case in
p0109 is "easy" in the sense that the non-member op=
erators
for primitive types are always defined before copies can
be made, so they can surely be seen in the copy.<br>
</div>
=20
=20
=20
=20
<br>
p0109 manages with classes as underling types also.<span class=3D"gmail=
-im"><br></span></blockquote><div><br></div><div>Yes, of course. I meant th=
e energy example.<br><br><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">=
<span class=3D"gmail-im"><blockquote type=3D"cite"><div dir=3D"ltr"><div><d=
iv><div>One could argue that such a problem does not exist,
since the new function can be made template from the start
and so apply to both A and B. Perhaps. I'm just asking th=
e
question out of completeness, I'm not sure what the answe=
r
should be.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
If B is copied later the following could be a possibility<br>
<br>
struct B : using A {<br>
=C2=A0=C2=A0=C2=A0 friend void foo(B b) =3D default;<br>
};<br></blockquote><div><br></div><div>This I like, although it does no=
t really need to be a friend, does it?<br><br><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex">Otherwise the user can do just:<br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b)=C2=A0 { foo(A(b)); };</blockquote><div=
><br></div><div>This won't do, as we don't necessarily want B to be=
convertible to A. There should be something like copy_cast<A>(b), bu=
t I don't like it.<br><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex">Maybe <br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b) =3D default;<span class=3D"gmail-im"><=
br></span></blockquote><div><br></div><div>=C2=A0This could work but it has=
the potential to be unclear, as this definition could happen far away from=
B so it has less context. Maybe just restricting us to the case where all =
needed non-member functions have already been declared is still enough. I w=
ould do that for the moment.<br><br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex">You lost me. My copy is not the same as yours. I don't copy =
the
function code, as I don't have access to it. It is not a template a=
t
all. The copied function is wrapping the existing functions.<br>
<br>
<div>double foo(A a) {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 return foo(B(a);<br>
</div>
}</blockquote><div><br></div><div>If A is convertible to B, you don'=
;t need a new way to declare a trampoline at all. The lines you wrote are e=
nough (and I think also short enough), no new syntax needs to be introduced=
.. It wouldn't matter if A is a copy of B or not.<br><br></div><div>If A=
is not directly convertible to B, what I said stands.<br><br>If you want t=
o assume that B and A have the same underlying representation, you could tr=
y casting them bit by bit. But this would be equivalent to<br><br></div><di=
v>double foo(A a) {<br></div><div>=C2=A0=C2=A0=C2=A0 return foo(*reinterpre=
t_cast<B*>(a));<br>}<br><br></div><div>which is undefined behaviour i=
n 90% of cases, even if the two classes are literally identical (as they mu=
st be standard_layout for it to be valid in C++, for some reason). So this =
is not going to work either. As in:<br><br></div><div>struct A {<br></div><=
div>=C2=A0=C2=A0=C2=A0 int a;<br></div><div>=C2=A0=C2=A0=C2=A0 private:<br>=
</div><div>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int b;<br></div><div>=
};<br><br></div><div>struct B {<br></div><div>=C2=A0=C2=A0=C2=A0 int a;<br>=
</div><div>=C2=A0=C2=A0=C2=A0 private:<br></div><div>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 int b;<br>};<br><br></div><div>A a;<br></div><div>aut=
o b =3D *reinterpret_cast<B*>(a); // undefined behaviour<br><br></div=
><div>This is undefined behaviour by the current standard. This proposal (a=
nd assume also p0109) rests on the assumption that this undefined behaviour=
can be relaxed when we explicitly define a class to be a copy of another.<=
br><br></div><div>Otherwise you'd have to first try a proposal to chang=
e how reinterpret_cast work. However, as it's behaviour is different fr=
om C, I assume it has been deliberately modified for some reason (which I d=
on't know), so it probably won't be simple.<br><br></div><div>Best,=
<br></div><div>Eugenio<br></div></div></div></div></div></div><div class=3D=
"gmail_extra"><br><div class=3D"gmail_quote">On Tue, Jan 3, 2017 at 6:29 PM=
, Vicente J. Botet Escriba <span dir=3D"ltr"><<a href=3D"mailto:vicente.=
botet@wanadoo.fr" target=3D"_blank">vicente.botet@wanadoo.fr</a>></span>=
wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000"><div><div class=3D"h5">
<div class=3D"m_-2038834817066522304moz-cite-prefix">Le 03/01/2017 =C3=
=A0 12:31, Eugenio
Bargiacchi a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">
<div dir=3D"ltr">Dear Vicente,<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex=
;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=3D"m_=
-2038834817066522304gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>Well, in inheritance child classes can be
converted to their parents automatically (even if
they don't define a constructor that initializes an=
y
new data they might have). If that can be done I
don't see why this would be impossible for a copied
class + a new non-static data member to do the same
thing.<br>
</div>
</div>
</div>
</blockquote>
</span> You need to construct a derived from a base. If
derived contains more data you can not do it correctly.<br>
</blockquote>
<div><br>
</div>
<div>Well not necessarily. There are classes that take fewer
parameters than the number of their members. There are classes
that define a constructor with no parameters, even though they
have members. There are structs with no constructor at all. <br>
<br>
</div>
<div>For example, if you copy a class and add, say, an
std::vector, I'd say it would be very easy to create the copy
from the original, since the std::vector can initialize itself
very easily.<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Yes. I was miss=
ing all
the copies and I mixed base_type as the base type of
ConvertBack. Sorry for reading your code too quickly. <br>
<br>
I start liking your feature more and more. It could really
help to make easier to define opaque types. <br>
</blockquote>
<div><br>
</div>
<div>I'm really glad you like it!<br>
<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Note how <br>
<span class=3D"m_-2038834817066522304gmail-im"> <br>
template <typename C><br>
struct Plus : using C {<br>
</span><span class=3D"m_-2038834817066522304gmail-im"> =C2=A0=
=C2=A0=C2=A0 Plus operator+(Plus
other) { return Plus{t_ + other.t_}; }<br>
};<br>
<br>
</span> is close to=C2=A0 p0109<br>
<br>
template <typename C><br>
using Plus : private C {<br>
=C2=A0=C2=A0=C2=A0 Plus operator+(Plus x, Plus y) =3D default=
;<br>
};<span class=3D"m_-2038834817066522304gmail-im"><br>
</span></blockquote>
<div>=C2=A0<br>
</div>
<div>Yes. However, if non-member functions can be copied, I
believe there should exist a syntax to create them also
outside the copied class. Suppose:<br>
<br>
</div>
<div>// From library<br>
</div>
<div>struct A {};<br>
</div>
<div>struct B : using A {}<br>
<br>
</div>
<div>// User defined<br>
</div>
<div>void foo(A a) {}<br>
</div>
<div>// How to define foo(B)?<br>
<br>
</div>
<div>The problem with this example is that when foo(A) is
defined, B has already been defined. The original case in
p0109 is "easy" in the sense that the non-member op=
erators
for primitive types are always defined before copies can
be made, so they can surely be seen in the copy.<br>
</div>
</div>
</div>
</div>
</blockquote>
<br></div></div>
p0109 manages with classes as underling types also.<span class=3D""><br=
>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
</div>
<div>One could argue that such a problem does not exist,
since the new function can be made template from the start
and so apply to both A and B. Perhaps. I'm just asking th=
e
question out of completeness, I'm not sure what the answe=
r
should be.<br>
</div>
</div>
</div>
</div>
</blockquote></span>
If B is copied later the following could be a possibility<br>
<br>
struct B : using A {<br>
=C2=A0=C2=A0=C2=A0 friend void foo(B b) =3D default;<br>
};<br>
<br>
Otherwise the user can do just:<br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b)=C2=A0 { foo(A(b)); };<br>
<br>
I don't know if it is worth providing something else to take care o=
f
this function copy.<br>
Maybe <br>
<br>
=C2=A0=C2=A0=C2=A0 void foo(B b) =3D default;<span class=3D""><br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=
=3D"m_-2038834817066522304gmail-im">
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>If not, why not? Are you
constrained in doing this only in
copied class and with functions
taking/returning the original class,
maybe? Why?<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</span> No. You could substitute any type T by a type U
if U(T(u)) =3D=3D u as the trampoline is doing just this
double conversion. The particularity of opaque types is
that the conversion costs nothing as both classes share
the same representation. For other types, the cost of
the conversions could be more visible.</blockquote>
<div><br>
</div>
<div>I'm not sure that definition always holds,
unfortunately. You'd have to force them to have the sam=
e
public interface, or else maybe the conversion from
U->T->U will work, but T has a different interface
so they are not compatible. Consider:<br>
<br>
</div>
<div>struct A {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 A() : x_(0) {}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int x_;<br>
</div>
<div>};<br>
<br>
</div>
<div>struct B {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 B(A a) : d_(5), i_(a.x_) {}<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 operator A() { return A{i_}; } =C2=A0=
<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 <br>
=C2=A0=C2=A0=C2=A0 double d_;<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 int i_;<br>
</div>
<div>};<br>
<br>
</div>
<div>double foo(B b) {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 return b.d_ + b.i_;<br>
</div>
<div>}<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>If you just follow the conversion rules, then you
could convert foo(B) into foo(A), since A(B(a)) =3D=3D a fo=
r
any a.</div>
</div>
</div>
</div>
</div>
</blockquote></span>
Right.
<span class=3D""><blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div> However, it would fail to compile as of course B and
A do not have the same interface. You'd have to
guarantee that when converting A to B that A has at
least the same interface as B (which is the same as
copying, pretty much, even though it does not require it
since one could do this by hand). This includes static
members, typedefs, etc etc. It would also include
non-member functions possibly - if foo uses them.<br>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote></span>
You lost me. My copy is not the same as yours. I don't copy the
function code, as I don't have access to it. It is not a template a=
t
all. The copied function is wrapping the existing functions.<br>
<br>
<div>double foo(A a) {<br>
</div>
<div>=C2=A0=C2=A0=C2=A0 return foo(B(a);<br>
</div>
}<br>
<br>
When one type is the opaque type of the other the conversion is
trivial and so there is no need of trampoline in realiyt. Only the
compiler must check the types and call to the base function.<span class=
=3D""><br>
<br>
<blockquote type=3D"cite">
<div dir=3D"ltr">
<div>
<div>
<div>
<div>The only way to practically make that check would be
to just let the compiler try, probably. Which would be
equivalent to transforming foo into a templated
function. Which I'm not sure is going to get accepted.<=
br>
</div>
<div><br>
</div>
<br>
</div>
</div>
</div>
</div>
</blockquote></span>
Vicente<br>
<br>
</div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/44d44d44-483e-1ee5-90a7-1a4b966858f5%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/44d4=
4d44-483e-1ee5-<wbr>90a7-1a4b966858f5%40wanadoo.fr</a><wbr>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2Bt59Uu0u6F6GJue7yaJOgffLh_7=
WpoKC%2Bfky32oGfhK0Q%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
t59Uu0u6F6GJue7yaJOgffLh_7WpoKC%2Bfky32oGfhK0Q%40mail.gmail.com</a>.<br />
--94eb2c041276f359e8054534bca1--
.
Author: Alex Newlifer <alex.newlifer@gmail.com>
Date: Thu, 20 Jul 2017 02:25:52 -0700 (PDT)
Raw View
------=_Part_366_538788357.1500542752944
Content-Type: multipart/alternative;
boundary="----=_Part_367_1015792004.1500542752946"
------=_Part_367_1015792004.1500542752946
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Hello!
I suggest to use `explicit` specifier for using-declaration to make strong
typedef (aka completely new type).
Simple example:
```
using explicit my_int_t =3D int;
/* Now we cannot pass into function foo int values without explicit cast.
*/
void foo(my_int_t val)
{}
int val =3D 0;
foo(val); // Error
foo(static_cast<my_int_t>(val)); // Ok
foo(my_int_t(0)); // Ok
```
=D0=BF=D0=BE=D0=BD=D0=B5=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA, 19 =D0=
=B4=D0=B5=D0=BA=D0=B0=D0=B1=D1=80=D1=8F 2016 =D0=B3., 14:04:48 UTC+3 =D0=BF=
=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=20
sval...@gmail.com =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB:
>
> This is a stub proposal on strong typedefs, i.e. types that work in the=
=20
> exact same way, but allow separate overloading. Other papers and proposal=
s=20
> exist, but I've tried a different approach that tries to mimic a more=20
> inheritance-like syntax which might be more intuitive. The full text can =
be=20
> found online at https://github.com/Svalorzen/CppCopyProposal.
>
> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text below.=
=20
> Thanks in advance for your comments.
>
> Duplication and Extension of Existing Classes
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Introduction
> ------------
>
> This document describes a possible approach to duplicate existing=20
> functionality
> while wrapping it in a new type, without the burden of inheritance and to=
=20
> allow
> function overloads on syntactically identical but semantically different=
=20
> types
> (also known as *strong typedef*).
>
> The approach taken should be simple to implement and be applicable to=20
> existing
> code.
>
> Optional sections are to be read as additional ideas that could be furthe=
r
> developed or completely ignored. They are mostly food for thought, but=20
> included
> for completeness.
>
> Reasons
> -------
>
> - Scientific libraries where a type has different behaviors depending on=
=20
> context
> have currently no simple way to indicate the semantic differences. Sinc=
e=20
> a
> `typedef` does not allow multiple overloads on new typedef types - sinc=
e=20
> they
> are still the "old" type - they have to resort to imperfect techniques,=
=20
> such
> as copying, wrapping or inheriting the needed type. Examples:=20
> coordinates in a
> plane (rectangular, polar), vectors of double (probabilities, values).
> - Easier maintainability of code which is known to be the same, rather th=
an
> being copy-pasted.
> - Avoiding misuse of inheritance in order to provide a copy-paste=20
> alternative.
> This can result in very deep hierarchies of types which should really=
=20
> not have
> anything to do with each other.
> - Enabling users to use an existing and presumably correct type but=20
> partially
> extend it with context-specific methods. Examples: search for=20
> "`std::vector`
> inheritance" yields many results of users trying to maintain the origin=
al
> interface and functionality but add one or two methods.
>
> The functionality should have the following requirements:
>
> - Can be applied to existing code.
> - Should limit dependencies between new and old type as much as possible.
> - Should allow for partial extensions of the old code.
>
> Alternatives
> ------------
>
> ### Typedef / Using Directive ###
>
> Using a type alias creates an alternative name for a single type. However=
,=20
> this
> leaves no space to implement overloads that are context-specific. Nor a=
=20
> type can
> be extended in a simple way while keeping the old interface intact.
>
> ### Inheritance ###
>
> Inheritance requires redefinition of all constructors, and creates a=20
> stricter
> dependency between two classes than what is proposed here. Classes may be
> converted to a common ancestor even though that is undesired or even=20
> dangerous
> in case of implicit conversions.
>
> Inheritance may also be unwanted in order to avoid risks linked to=20
> polymorphism
> and freeing data structures where the base class does not have a virtual
> destructor.
>
> ### Encapsulation with Manual Exposure of Needed Methods ###
>
> This method obviously requires a great deal of code to be rewritten in=20
> order to
> wrap every single method that the old class was exposing.
>
> In addition one needs to have intimate knowledge of the original interfac=
e=20
> in
> order to be able to duplicate it correctly. Template methods, rvalue=20
> references,
> possibly undocumented methods which are required in order to allow the=20
> class to
> behave in the same way as before. This heightens the bar significantly fo=
r=20
> many
> users, since they may not know correctly how to duplicate an interface an=
d=20
> how
> to forward parameters to the old interface correctly.
>
> The new code also must be maintained in case the old interface changes.
>
> ### Copying the Base Class ###
>
> This can be useful, but requires all code to be duplicated, and thus
> significantly increases the burden of maintaining the code. All bugs=20
> discovered
> in one class must be fixed in the other class too. All new features=20
> applied to
> one class must be applied to the other too.
>
> ### Macro-expansion ###
>
> Macro expansions can be used in order to encode the interface and=20
> implementation
> of a given class just one time, and used multiple times to produce separa=
te
> classes.
>
> This approach is unfortunately not applicable to existing code, and is=20
> very hard
> to extend if one wants to copy a class but add additional functionality t=
o=20
> it.
>
> ### Templates ###
>
> Templates produce for each instantiation a separate type. They are=20
> unfortunately
> not applicable to previously existing code. For new code, they would=20
> require the
> creation of "fake" template parameters that would need to vary in order t=
o
> produce separate types.
>
> In addition, class extension through templates is not possible: variation=
s=20
> would
> need to be made through specialization, which itself requires copying=20
> existing
> code.
>
> Previous Work
> -------------
>
> Strong typedefs have already been proposed for the C++ language multiple=
=20
> times
> ([N1706](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pd=
f
> ),
> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf
> ),
> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
> ),
> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are=
=20
> named
> *opaque typedefs*, and these papers try to explore and define exactly the
> behavior that such typedefs should and would have when used to create new
> types. In particular, the keywords `public`, `protected` and `private` ar=
e=20
> used
> in order to create a specific relation with the original type and how is=
=20
> the
> new type allowed to be cast back to the original type or be used in its=
=20
> place
> during overloads.
>
> This document shares many of the the same principles, for example (quotin=
g=20
> from
> N3741):
>
> > - Consistent with restrictions imposed on analogous relationships such =
as
> > base classes underlying derived classes and integer types underlying=
=20
> enums,
> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We=20
> also do
> > not require that any enum type, reference type, array type, function=
=20
> type, or
> > pointer-to-member type be allowed as an underlying type.
>
> However, this document tries to propose a possibly more simple approach,=
=20
> where
> a new language feature is introduced with the same meaning and=20
> functionality as
> if the user autonomously implemented a new class him/herself, matching th=
e
> original type completely. Thus, it should result for the user more simple=
=20
> to
> understand (as it simply matches already the already understood mechanics=
=20
> of
> creating a new, unique type from nothing), and no new rules for type=20
> conversion
> and selection on overloads have to be created.
>
> Syntax
> ------
>
> ### Simple Case ###
>
> Syntax could look something like this:
>
> ```cpp
> class Base {
> public:
> Base() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> struct Copy : using Base {};
>
> /* Equivalent to
>
> struct Copy {
> public:
> Copy() : x(0) {}
> void foo() { std::cout << "foo " << x << "\n"; }
> private:
> int x;
> };
>
> */
> ```
>
> One cannot copy a class and inherit at the same time. If such a class is=
=20
> needed
> one would need to create it by hand with the desided functionality and
> inheriting from the desired classes, as it would be done normally.
>
> All method implementations would be the same. The copied class would=20
> inherit
> from the same classes its base class inherits from. All constructors woul=
d=20
> work
> in the same way.
>
> ### Adding New Functionality ###
>
> Ideally one could specify additional methods, separate from that of Base,=
=20
> to add
> upon the existing functionality.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> };
>
> struct Derived : public Base {};
>
> struct Copy : using Base {
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : using Derived {};
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct CopyDerived : public Base {};
>
> */
> ```
>
> Only new methods need to be implemented for that class.
>
> #### Interfacing with the Original Class ####
>
> In order to interface with the original class, simple conversion operator=
s=20
> can
> be added by the user explicitly at-will, in order to obtain the desired
> interface. Note that if more types with this kind of compatibility were=
=20
> needed,
> one would only need to implement them once, since copying the produced ty=
pe
> would copy the new, more compatible interface with it.
>
> ```cpp
> struct Base {
> public:
> int x;
>
> private:
> double y;
> };
>
> struct Copy : using Base {
> operator Base() { return Base{x, y}; }
> };
> ```
>
> `reinterpret_cast` may also be used to convert back to the original class=
,
> limited by the tool's already existing rules.
>
> In general the usual rules of `reinterpret_cast` apply to the copied=20
> classes
> with respect to their general classes, exactly as if the copied class had=
=20
> been
> implemented by hand.
>
> ### Overloads ###
>
> Duplicating an existing class should allow for new overloads on the new=
=20
> type,
> and no ambiguity between the copied class, the old class and other copied
> classes.
>
> ```cpp
> class Position : using std::pair<double, double> {};
> class Distance : using std::pair<double, double> {};
>
> Position operator+(const Position & p, const Distance & d) {
> return Position(p.first + d.first, p.second + d.second);
> }
>
> Distance operator+(const Distance & lhs, const Distance & rhs) {
> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
> }
>
> // ...
>
> Position p(1, 1);
> Distance d(1, 1);
>
> p + d; // OK
> d + d; // OK
> p + p; // Error
> ```
>
> ### Templated Class Copy ###
>
> The user might want to create a single templatized copy interface, and us=
e=20
> it
> multiple times. For example, one might want multiple copied classes which=
=20
> can
> convert to their original. This could be done as follows:
>
> ```cpp
> struct A { int x; };
>
> template <typename T>
> struct TemplatizedCopy : using T {
> static_assert(std::is_standard_layout<T>::value,
> "Can't use this with a non-standard-layout class");
>
> operator T&() { return *reinterpret_cast<T*>(this); }
> };
>
> // Could be used either via normal typedefs
> using Copy1 =3D TemplatizedCopy<A>;
>
> // Or via copy, depending on requirements.
> struct Copy2 : using TemplatizedCopy<A> {};
> ```
>
> ### Copying Template Classes ###
>
> Since the construct is similar to inheritance, the syntax for creating=20
> aliases
> of templated classes could be the same:
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B : using A<T> {};
>
> B<int> b;
> ```
>
> The copied class must have the same number or less of template parameters=
=20
> than
> the base class. Partial or full specializations of the base class can be=
=20
> allowed:
>
> ```cpp
> template <typename T, typename U>
> struct A {};
>
> template <typename T>
> struct B : using A<T, double> {};
>
> B<int> b;
> ```
>
> When the base class has partial specializations, only those who apply are=
=20
> copied
> to the copied class.
>
> ```cpp
> template <typename T, typename U>
> struct A { T t; U u; };
>
> template <typename U>
> struct A<double, U> { double y; U u; };
>
> template <typename T>
> struct A<T, int> { T t; char z; };
>
> template <typename T>
> struct B : using A<T, double> {};
>
> /* Equivalent to
>
> template <typename T>
> struct B { T t; double u; };
>
> template <>
> struct B<double> { double y; double u; };
>
> */
> ```
>
> The copied class can add additional specializations. Or specializations=
=20
> for a
> given class can copy another.
>
> ```cpp
> template <typename T>
> struct A { int x; };
>
> struct B { char c; };
>
> template <typename T>
> struct C : using A<T> {};
>
> template <>
> struct C<double> : using B {};
>
> template <>
> struct A<int> : using C<double> {};
>
> /* Equivalent to
>
> template<>
> struct A<int> { char c; };
>
> template <typename T>
> struct C { int x; };
>
> template <>
> struct C<double> { char c; };
>
> */
> ```
>
> ### Copying Multiple Dependent Classes ###
>
> Copying multiple classes using the simple syntax we have described can be
> impossible if those classes depend on one another. This is because each=
=20
> copy
> would depend on the originals, rather than on the copied classes. A=20
> possible way
> to specify such dependencies could be:
>
> ```cpp
> struct A;
>
> struct B {
> A * a;
> };
>
> struct A {
> B b;
> };
>
> struct C;
>
> struct D : using B {
> using class C =3D A;
> };
>
> struct C : using A {
> using class D =3D B;
> };
>
> /* Equivalent to
>
> struct C;
>
> struct D {
> C * a;
> };
>
> struct C {
> D b;
> };
>
> */
> ```
>
> `using class` has been used in order to disambiguate it from normal `usin=
g`
> alias directive. `using class` is only valid when the left hand side has=
=20
> been
> defined as a copy of the right hand side.
>
> In case of a template base class using a template second class, one could
> specify different copies for certain specializations;
>
> ```cpp
> template <typename T>
> struct A {};
>
> template <typename T>
> struct B {
> A<T> a;
> };
>
> template <typename T>
> struct C : using A<T> {};
>
> ```
>
> ### Substituting Existing Functionality (Optional) ###
>
> Ideally one may want to use most of an implementation for another class,=
=20
> but
> vary a certain number of methods. In this case, if `Copy` contains a memb=
er
> function that already exists in `Base`, then that implementation is=20
> substituted
> in `Copy`. This may or may not be allowed for attributes.
>
> ```cpp
> struct Base {
> void foo() { std::cout << "foo\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> struct Copy : using Base {
> void foo() { std::cout << "baz\n"; }
> };
>
> /* Equivalent to
>
> struct Copy {
> void foo() { std::cout << "baz\n"; }
> void bar() { std::cout << "bar\n"; }
> };
>
> */
> ```
>
> A side effect of this is that it could allow for some type of "interface"=
,=20
> where
> some base class could be defined as:
>
> ```cpp
> struct Base {
> Base() =3D delete;
> void foo();
> void bar();
> };
>
> struct Copy1 : using Base {
> Copy1() =3D default;
> void baz();
> void foo() =3D delete;
> };
>
> /* Equivalent to
>
> struct Copy1 {
> Copy1() =3D default;
> void bar();
> void baz();
> };
>
> */
>
> struct Copy2 : using Base {
> Copy2(int);
> void abc();
> };
>
> /*
>
> Equivalent to
>
> struct Copy2 {
> Copy2(int);
> void foo();
> void bar();
> void abc();
> };
>
> */
> ```
>
> This feature could however present problems when the members changed also=
=20
> alter
> behavior and/or variable types of non-modified member and non-member=20
> functions,
> since the new behavior could be either erroneous or ambiguous.
>
> ### Copying and Extending Primitive Types (Optional) ###
>
> The same syntax could be used in order to extend primitive types. Using t=
he
> extension that allows the modification of the copied types, this could=20
> allow for
> creation of numeric types where some operations are disabled as needed.
>
> ```cpp
> struct Id : using int {
> Id operator+(Id, Id) =3D delete;
> Id operator*(Id, Id) =3D delete;
> // Non-explicitly deleted operators keep their validity
>
> // Defining new operators with the old type can allow interoperativit=
y
> Id operator+(Id, int);
> // We can convert the copied type to the old one.
> operator int() { return (*this) * 2; }
> };
>
> /* Equivalent to
>
> class Id final {
> public:
> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>
> Id operator+(Id, int);
> operator int() { return v_ * 2; }
> private:
> int v_;
> };
>
> */
> ```
>
> Note that when copying from a primitive types inheritance is forbidden as=
=20
> the
> generated copy is `final` (although it is allowed to keep copying the new=
ly
> created class).
>
> ### STL Traits (Optional) ###
>
> Traits could be included in the standard library in order to determine=20
> whether a
> class is a copy of another, or if it has been derived from a copy
> (copies/inheritances could be nested arbitrarily).
>
> ```cpp
> struct Base {};
>
> struct Copy : using Base {};
>
> static_assert(std::is_copy<Copy, Base>::value);
>
> struct ChildCopy : public Copy {};
>
> struct CopyChildCopy : using ChildCopy {};
>
> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
> ```
>
> Compatibility
> -------------
>
> As the syntax is new, no old code would be affected.
>
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/6718363e-3517-4af2-aa5f-9f0dd436c14b%40isocpp.or=
g.
------=_Part_367_1015792004.1500542752946
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hello!</div><div><br></div><div>I suggest to use `exp=
licit` specifier for using-declaration to make strong</div><div>typedef (ak=
a completely new type).</div><div><br></div><div>Simple example:</div><div>=
```</div><div>using explicit my_int_t =3D int;</div><div><br></div><div>/* =
Now we cannot pass into function foo int values without explicit cast.</div=
><div>*/</div><div>void foo(my_int_t val)</div><div>{}</div><div><br></div>=
<div>int val =3D 0;</div><div><br></div><div>foo(val); // Error</div><div>f=
oo(static_cast<my_int_t>(val)); // Ok</div><div>foo(my_int_t(0)); // =
Ok</div><div>```</div><div><br></div><br>=D0=BF=D0=BE=D0=BD=D0=B5=D0=B4=D0=
=B5=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA, 19 =D0=B4=D0=B5=D0=BA=D0=B0=D0=B1=D1=80=
=D1=8F 2016 =D0=B3., 14:04:48 UTC+3 =D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=
=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C sval...@gmail.com =D0=BD=D0=B0=D0=BF=D0=
=B8=D1=81=D0=B0=D0=BB:<blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr">This is a stub proposal on strong typedefs, i.e. types that work i=
n the exact same way, but allow separate overloading. Other papers and prop=
osals exist, but I've tried a different approach that tries to mimic a =
more inheritance-like syntax which might be more intuitive. The full text c=
an be found online at <a href=3D"https://github.com/Svalorzen/CppCopyPropos=
al" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'http=
s://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCopyP=
roposal\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQ=
w';return true;" onclick=3D"this.href=3D'https://www.google.com/url=
?q\x3dhttps%3A%2F%2Fgithub.com%2FSvalorzen%2FCppCopyProposal\x26sa\x3dD\x26=
sntz\x3d1\x26usg\x3dAFQjCNH4h4ontLAyhulf7sjCIvww-EQKQw';return true;">h=
ttps://github.com/Svalorzen/<wbr>CppCopyProposal.<br><br></a>I'm copyin=
g the text below. Thanks in advance for your comments.<br><br><span style=
=3D"font-family:courier new,monospace">Duplication and Extension of Existin=
g Classes<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<wbr>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D<br><br>Introduction<br>------------<br><br>This document describes a=
possible approach to duplicate existing functionality<br>while wrapping it=
in a new type, without the burden of inheritance and to allow<br>function =
overloads on syntactically identical but semantically different types<br>(a=
lso known as *strong typedef*).<br><br>The approach taken should be simple =
to implement and be applicable to existing<br>code.<br><br>Optional section=
s are to be read as additional ideas that could be further<br>developed or =
completely ignored. They are mostly food for thought, but included<br>for c=
ompleteness.<br><br>Reasons<br>-------<br><br>- Scientific libraries where =
a type has different behaviors depending on context<br>=C2=A0 have currentl=
y no simple way to indicate the semantic differences. Since a<br>=C2=A0 `ty=
pedef` does not allow multiple overloads on new typedef types - since they<=
br>=C2=A0 are still the "old" type - they have to resort to imper=
fect techniques, such<br>=C2=A0 as copying, wrapping or inheriting the need=
ed type. Examples: coordinates in a<br>=C2=A0 plane (rectangular, polar), v=
ectors of double (probabilities, values).<br>- Easier maintainability of co=
de which is known to be the same, rather than<br>=C2=A0 being copy-pasted.<=
br>- Avoiding misuse of inheritance in order to provide a copy-paste altern=
ative.<br>=C2=A0 This can result in very deep hierarchies of types which sh=
ould really not have<br>=C2=A0 anything to do with each other.<br>- Enablin=
g users to use an existing and presumably correct type but partially<br>=C2=
=A0 extend it with context-specific methods. Examples: search for "`st=
d::vector`<br>=C2=A0 inheritance" yields many results of users trying =
to maintain the original<br>=C2=A0 interface and functionality but add one =
or two methods.<br><br>The functionality should have the following requirem=
ents:<br><br>- Can be applied to existing code.<br>- Should limit dependenc=
ies between new and old type as much as possible.<br>- Should allow for par=
tial extensions of the old code.<br><br>Alternatives<br>------------<br><br=
>### Typedef / Using Directive ###<br><br>Using a type alias creates an alt=
ernative name for a single type. However, this<br>leaves no space to implem=
ent overloads that are context-specific. Nor a type can<br>be extended in a=
simple way while keeping the old interface intact.<br><br>### Inheritance =
###<br><br>Inheritance requires redefinition of all constructors, and creat=
es a stricter<br>dependency between two classes than what is proposed here.=
Classes may be<br>converted to a common ancestor even though that is undes=
ired or even dangerous<br>in case of implicit conversions.<br><br>Inheritan=
ce may also be unwanted in order to avoid risks linked to polymorphism<br>a=
nd freeing data structures where the base class does not have a virtual<br>=
destructor.<br><br>### Encapsulation with Manual Exposure of Needed Methods=
###<br><br>This method obviously requires a great deal of code to be rewri=
tten in order to<br>wrap every single method that the old class was exposin=
g.<br><br>In addition one needs to have intimate knowledge of the original =
interface in<br>order to be able to duplicate it correctly. Template method=
s, rvalue references,<br>possibly undocumented methods which are required i=
n order to allow the class to<br>behave in the same way as before. This hei=
ghtens the bar significantly for many<br>users, since they may not know cor=
rectly how to duplicate an interface and how<br>to forward parameters to th=
e old interface correctly.<br><br>The new code also must be maintained in c=
ase the old interface changes.<br><br>### Copying the Base Class ###<br><br=
>This can be useful, but requires all code to be duplicated, and thus<br>si=
gnificantly increases the burden of maintaining the code. All bugs discover=
ed<br>in one class must be fixed in the other class too. All new features a=
pplied to<br>one class must be applied to the other too.<br><br>### Macro-e=
xpansion ###<br><br>Macro expansions can be used in order to encode the int=
erface and implementation<br>of a given class just one time, and used multi=
ple times to produce separate<br>classes.<br><br>This approach is unfortuna=
tely not applicable to existing code, and is very hard<br>to extend if one =
wants to copy a class but add additional functionality to it.<br><br>### Te=
mplates ###<br><br>Templates produce for each instantiation a separate type=
.. They are unfortunately<br>not applicable to previously existing code. For=
new code, they would require the<br>creation of "fake" template =
parameters that would need to vary in order to<br>produce separate types.<b=
r><br>In addition, class extension through templates is not possible: varia=
tions would<br>need to be made through specialization, which itself require=
s copying existing<br>code.<br><br>Previous Work<br>-------------<br><br>St=
rong typedefs have already been proposed for the C++ language multiple time=
s<br>([N1706](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers=
/2004/n1706.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.hre=
f=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjtc=
1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sntz\x3d1\=
x26usg\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;" onclick=3D"=
this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.o=
rg%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2004%2Fn1706.pdf\x26sa\x3dD\x26sn=
tz\x3d1\x26usg\x3dAFQjCNEGleYuUYy8G59_eDbnN11KwFn0VQ';return true;">htt=
p://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2004/n1706.pdf</a=
>),<br>[N1891](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/paper=
s/2005/n1891.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.hr=
ef=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fjt=
c1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26sntz\x3d1=
\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;" onclick=3D=
"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.=
org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2005%2Fn1891.pdf\x26sa\x3dD\x26s=
ntz\x3d1\x26usg\x3dAFQjCNFQAJlPBYO5Z5Jl5_Xy3fqKa1lmPA';return true;">ht=
tp://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2005/n1891.pdf</=
a>),<br>[N3515](<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/pape=
rs/2013/n3515.pdf" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.h=
ref=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-std.org%2Fj=
tc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x26sntz\x3d=
1\x26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;" onclick=
=3D"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.open-s=
td.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2013%2Fn3515.pdf\x26sa\x3dD\x=
26sntz\x3d1\x26usg\x3dAFQjCNHA18OHTi46Xo80VTjRf_GK7PtwMg';return true;"=
>http://www.open-std.<wbr>org/jtc1/sc22/wg21/docs/<wbr>papers/2013/n3515.pd=
f</a>),<br>[N3741](<a href=3D"https://isocpp.org/files/papers/n3741.pdf)" t=
arget=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'https://w=
ww.google.com/url?q\x3dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pd=
f)\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA'=
;;return true;" onclick=3D"this.href=3D'https://www.google.com/url?q\x3=
dhttps%3A%2F%2Fisocpp.org%2Ffiles%2Fpapers%2Fn3741.pdf)\x26sa\x3dD\x26sntz\=
x3d1\x26usg\x3dAFQjCNFsO-HZdSZm41tTzZev2nxIpJkHZA';return true;">https:=
//isocpp.org/<wbr>files/papers/n3741.pdf)</a>). These typedefs are named<br=
>*opaque typedefs*, and these papers try to explore and define exactly the<=
br>behavior that such typedefs should and would have when used to create ne=
w<br>types. In particular, the keywords `public`, `protected` and `private`=
are used<br>in order to create a specific relation with the original type =
and how is the<br>new type allowed to be cast back to the original type or =
be used in its place<br>during overloads.<br><br>This document shares many =
of the the same principles, for example (quoting from<br>N3741):<br><br>>=
; - Consistent with restrictions imposed on analogous relationships such as=
<br>>=C2=A0=C2=A0 base classes underlying derived classes and integer ty=
pes underlying enums,<br>>=C2=A0=C2=A0 an underlying type should be (1) =
complete and (2) not cv-quali=EF=AC=81ed. We also do<br>>=C2=A0=C2=A0 no=
t require that any enum type, reference type, array type, function type, or=
<br>>=C2=A0=C2=A0 pointer-to-member type be allowed as an underlying typ=
e.<br><br>However, this document tries to propose a possibly more simple ap=
proach, where<br>a new language feature is introduced with the same meaning=
and functionality as<br>if the user autonomously implemented a new class h=
im/herself, matching the<br>original type completely. Thus, it should resul=
t for the user more simple to<br>understand (as it simply matches already t=
he already understood mechanics of<br>creating a new, unique type from noth=
ing), and no new rules for type conversion<br>and selection on overloads ha=
ve to be created.<br><br>Syntax<br>------<br><br>### Simple Case ###<br><br=
>Syntax could look something like this:<br><br>```cpp<br>class Base {<br>=
=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Ba=
se() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { s=
td::cout << "foo " << x << "\n"; }<br=
>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
int x;<br>};<br><br>struct Copy : using Base {};<br><br>/* Equivalent to<br=
><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 void foo() { std::cout << "foo " << x <&=
lt; "\n"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br><br>One cannot co=
py a class and inherit at the same time. If such a class is needed<br>one w=
ould need to create it by hand with the desided functionality and<br>inheri=
ting from the desired classes, as it would be done normally.<br><br>All met=
hod implementations would be the same. The copied class would inherit<br>fr=
om the same classes its base class inherits from. All constructors would wo=
rk<br>in the same way.<br><br>### Adding New Functionality ###<br><br>Ideal=
ly one could specify additional methods, separate from that of Base, to add=
<br>upon the existing functionality.<br><br>```cpp<br>struct Base {<br>=C2=
=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<br>};<=
br><br>struct Derived : public Base {};<br><br>struct Copy : using Base {<b=
r>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<b=
r>};<br><br>struct CopyDerived : using Derived {};<br><br>/* Equivalent to<=
br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << =
"foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << =
"bar\n"; }<br>};<br><br>struct CopyDerived : public Base {};<br><=
br>*/<br>```<br><br>Only new methods need to be implemented for that class.=
<br><br>#### Interfacing with the Original Class ####<br><br>In order to in=
terface with the original class, simple conversion operators can<br>be adde=
d by the user explicitly at-will, in order to obtain the desired<br>interfa=
ce. Note that if more types with this kind of compatibility were needed,<br=
>one would only need to implement them once, since copying the produced typ=
e<br>would copy the new, more compatible interface with it.<br><br>```cpp<b=
r>struct Base {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struct Copy : usin=
g Base {<br>=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>};=
<br>```<br><br>`reinterpret_cast` may also be used to convert back to the o=
riginal class,<br>limited by the tool's already existing rules.<br><br>=
In general the usual rules of `reinterpret_cast` apply to the copied classe=
s<br>with respect to their general classes, exactly as if the copied class =
had been<br>implemented by hand.<br><br>### Overloads ###<br><br>Duplicatin=
g an existing class should allow for new overloads on the new type,<br>and =
no ambiguity between the copied class, the old class and other copied<br>cl=
asses.<br><br>```cpp<br>class Position : using std::pair<double, double&=
gt; {};<br>class Distance : using std::pair<double, double> {};<br><b=
r>Position operator+(const Position & p, const Distance & d) {<br>=
=C2=A0=C2=A0=C2=A0 return Position(p.first + d.first, p.second + d.second);=
<br>}<br><br>Distance operator+(const Distance & lhs, const Distance &a=
mp; rhs) {<br>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rhs.first, lhs=
..second + rhs.second);<br>}<br><br>// ...<br><br>Position p(1, 1);<br>Dista=
nce d(1, 1);<br><br>p + d; // OK<br>d + d; // OK<br>p + p; // Error<br>```<=
br><br>### Templated Class Copy ###<br><br>The user might want to create a =
single templatized copy interface, and use it<br>multiple times. For exampl=
e, one might want multiple copied classes which can<br>convert to their ori=
ginal. This could be done as follows:<br><br>```cpp<br>struct A { int x; };=
<br><br>template <typename T><br>struct TemplatizedCopy : using T {<b=
r>=C2=A0=C2=A0=C2=A0 static_assert(std::is_<wbr>standard_layout<T>::v=
alue,<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Can't use this with a non-st=
andard-layout class");<br><br>=C2=A0=C2=A0=C2=A0 operator T&() { r=
eturn *reinterpret_cast<T*>(this); }<br>};<br><br>// Could be used ei=
ther via normal typedefs<br>using Copy1 =3D TemplatizedCopy<A>;<br><b=
r>// Or via copy, depending on requirements.<br>struct Copy2 : using Templa=
tizedCopy<A> {};<br>```<br><br>### Copying Template Classes ###<br><b=
r>Since the construct is similar to inheritance, the syntax for creating al=
iases<br>of templated classes could be the same:<br><br>```cpp<br>template =
<typename T><br>struct A {};<br><br>template <typename T><br>st=
ruct B : using A<T> {};<br><br>B<int> b;<br>```<br><br>The copi=
ed class must have the same number or less of template parameters than<br>t=
he base class. Partial or full specializations of the base class can be all=
owed:<br><br>```cpp<br>template <typename T, typename U><br>struct A =
{};<br><br>template <typename T><br>struct B : using A<T, double&g=
t; {};<br><br>B<int> b;<br>```<br><br>When the base class has partial=
specializations, only those who apply are copied<br>to the copied class.<b=
r><br>```cpp<br>template <typename T, typename U><br>struct A { T t; =
U u; };<br><br>template <typename U><br>struct A<double, U> { d=
ouble y; U u; };<br><br>template <typename T><br>struct A<T, int&g=
t; { T t; char z; };<br><br>template <typename T><br>struct B : using=
A<T, double> {};<br><br>/* Equivalent to<br><br>template <typenam=
e T><br>struct B { T t; double u; };<br><br>template <><br>struct =
B<double> { double y; double u; };<br><br>*/<br>```<br><br>The copied=
class can add additional specializations. Or specializations for a<br>give=
n class can copy another.<br><br>```cpp<br>template <typename T><br>s=
truct A { int x; };<br><br>struct B { char c; };<br><br>template <typena=
me T><br>struct C : using A<T> {};<br><br>template <><br>str=
uct C<double> : using B {};<br><br>template <><br>struct A<i=
nt> : using C<double> {};<br><br>/* Equivalent to<br><br>template&=
lt;><br>struct A<int> { char c; };<br><br>template <typename T&=
gt;<br>struct C { int x; };<br><br>template <><br>struct C<double&=
gt; { char c; };<br><br>*/<br>```<br><br>### Copying Multiple Dependent Cla=
sses ###<br><br>Copying multiple classes using the simple syntax we have de=
scribed can be<br>impossible if those classes depend on one another. This i=
s because each copy<br>would depend on the originals, rather than on the co=
pied classes. A possible way<br>to specify such dependencies could be:<br><=
br>```cpp<br>struct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A * a;<br>};=
<br><br>struct A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>struct C;<br><br=
>struct D : using B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A;<br>};<br><=
br>struct C : using A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>};<br=
><br>/* Equivalent to<br><br>struct C;<br><br>struct D {<br>=C2=A0=C2=A0=C2=
=A0 C * a;<br>};<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<br>};<br><br>=
*/<br>```<br><br>`using class` has been used in order to disambiguate it fr=
om normal `using`<br>alias directive. `using class` is only valid when the =
left hand side has been<br>defined as a copy of the right hand side.<br><br=
>In case of a template base class using a template second class, one could<=
br>specify different copies for certain specializations;<br><br>```cpp<br>t=
emplate <typename T><br>struct A {};<br><br>template <typename T&g=
t;<br>struct B {<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><br>template =
<typename T><br>struct C : using A<T> {};<br><br>```<br><br>###=
Substituting Existing Functionality (Optional) ###<br><br>Ideally one may =
want to use most of an implementation for another class, but<br>vary a cert=
ain number of methods. In this case, if `Copy` contains a member<br>functio=
n that already exists in `Base`, then that implementation is substituted<br=
>in `Copy`. This may or may not be allowed for attributes.<br><br>```cpp<br=
>struct Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "=
foo\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "=
bar\n"; }<br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=
=A0 void foo() { std::cout << "baz\n"; }<br>};<br><br>/* Eq=
uivalent to<br><br>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::co=
ut << "baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::co=
ut << "bar\n"; }<br>};<br><br>*/<br>```<br><br>A side effec=
t of this is that it could allow for some type of "interface", wh=
ere<br>some base class could be defined as:<br><br>```cpp<br>struct Base {<=
br>=C2=A0=C2=A0=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 void foo();<=
br>=C2=A0=C2=A0=C2=A0 void bar();<br>};<br><br>struct Copy1 : using Base {<=
br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void baz()=
;<br>=C2=A0=C2=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/* Equivalent t=
o<br><br>struct Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=
=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<br>};<br><br>=
*/<br><br>struct Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=
=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>/*<br><br>Equivalent to<br><br>=
struct Copy2 {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void=
foo();<br>=C2=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void abc();=
<br>};<br><br>*/<br>```<br><br>This feature could however present problems =
when the members changed also alter<br>behavior and/or variable types of no=
n-modified member and non-member functions,<br>since the new behavior could=
be either erroneous or ambiguous.<br><br>### Copying and Extending Primiti=
ve Types (Optional) ###<br><br>The same syntax could be used in order to ex=
tend primitive types. Using the<br>extension that allows the modification o=
f the copied types, this could allow for<br>creation of numeric types where=
some operations are disabled as needed.<br><br>```cpp<br>struct Id : using=
int {<br>=C2=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete;<br>=C2=A0=C2=
=A0=C2=A0 Id operator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 // Non-exp=
licitly deleted operators keep their validity<br><br>=C2=A0=C2=A0=C2=A0 // =
Defining new operators with the old type can allow interoperativity<br>=C2=
=A0=C2=A0=C2=A0 Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0 // We can conv=
ert the copied type to the old one.<br>=C2=A0=C2=A0=C2=A0 operator int() { =
return (*this) * 2; }<br>};<br><br>/* Equivalent to<br><br>class Id final {=
<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id rhs) { return =
Id{lhs.v_ - rhs.v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id=
operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator=
int() { return v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<br><br>Note that=
when copying from a primitive types inheritance is forbidden as the<br>gen=
erated copy is `final` (although it is allowed to keep copying the newly<br=
>created class).<br><br>### STL Traits (Optional) ###<br><br>Traits could b=
e included in the standard library in order to determine whether a<br>class=
is a copy of another, or if it has been derived from a copy<br>(copies/inh=
eritances could be nested arbitrarily).<br><br>```cpp<br>struct Base {};<br=
><br>struct Copy : using Base {};<br><br>static_assert(std::is_copy<<wbr=
>Copy, Base>::value);<br><br>struct ChildCopy : public Copy {};<br><br>s=
truct CopyChildCopy : using ChildCopy {};<br><br>static_assert(std::is_copy=
_<wbr>base_of<Base, CopyChildCopy>::value);<br>```<br><br>Compatibili=
ty<br>-------------<br><br>As the syntax is new, no old code would be affec=
ted.<br></span><br></div></blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6718363e-3517-4af2-aa5f-9f0dd436c14b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6718363e-3517-4af2-aa5f-9f0dd436c14b=
%40isocpp.org</a>.<br />
------=_Part_367_1015792004.1500542752946--
------=_Part_366_538788357.1500542752944--
.
Author: =?UTF-8?Q?Micha=C5=82_Dominiak?= <griwes@griwes.info>
Date: Thu, 20 Jul 2017 09:28:00 +0000
Raw View
--94eb2c0ada6eff79ee0554bc5d59
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
I don't think the syntax is the main problem of this proposed direction;
write a paper with semantics described and publish it in a mailing.
On Thu, Jul 20, 2017 at 11:25 AM Alex Newlifer <alex.newlifer@gmail.com>
wrote:
> Hello!
>
> I suggest to use `explicit` specifier for using-declaration to make stron=
g
> typedef (aka completely new type).
>
> Simple example:
> ```
> using explicit my_int_t =3D int;
>
> /* Now we cannot pass into function foo int values without explicit cast.
> */
> void foo(my_int_t val)
> {}
>
> int val =3D 0;
>
> foo(val); // Error
> foo(static_cast<my_int_t>(val)); // Ok
> foo(my_int_t(0)); // Ok
> ```
>
>
> =D0=BF=D0=BE=D0=BD=D0=B5=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA, 19 =
=D0=B4=D0=B5=D0=BA=D0=B0=D0=B1=D1=80=D1=8F 2016 =D0=B3., 14:04:48 UTC+3 =D0=
=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C
> sval...@gmail.com =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB:
>
>> This is a stub proposal on strong typedefs, i.e. types that work in the
>> exact same way, but allow separate overloading. Other papers and proposa=
ls
>> exist, but I've tried a different approach that tries to mimic a more
>> inheritance-like syntax which might be more intuitive. The full text can=
be
>> found online at https://github.com/Svalorzen/CppCopyProposal.
>>
>> <https://github.com/Svalorzen/CppCopyProposal>I'm copying the text
>> below. Thanks in advance for your comments.
>>
>> Duplication and Extension of Existing Classes
>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>>
>> Introduction
>> ------------
>>
>> This document describes a possible approach to duplicate existing
>> functionality
>> while wrapping it in a new type, without the burden of inheritance and t=
o
>> allow
>> function overloads on syntactically identical but semantically different
>> types
>> (also known as *strong typedef*).
>>
>> The approach taken should be simple to implement and be applicable to
>> existing
>> code.
>>
>> Optional sections are to be read as additional ideas that could be furth=
er
>> developed or completely ignored. They are mostly food for thought, but
>> included
>> for completeness.
>>
>> Reasons
>> -------
>>
>> - Scientific libraries where a type has different behaviors depending on
>> context
>> have currently no simple way to indicate the semantic differences.
>> Since a
>> `typedef` does not allow multiple overloads on new typedef types -
>> since they
>> are still the "old" type - they have to resort to imperfect techniques=
,
>> such
>> as copying, wrapping or inheriting the needed type. Examples:
>> coordinates in a
>> plane (rectangular, polar), vectors of double (probabilities, values).
>> - Easier maintainability of code which is known to be the same, rather
>> than
>> being copy-pasted.
>> - Avoiding misuse of inheritance in order to provide a copy-paste
>> alternative.
>> This can result in very deep hierarchies of types which should really
>> not have
>> anything to do with each other.
>> - Enabling users to use an existing and presumably correct type but
>> partially
>> extend it with context-specific methods. Examples: search for
>> "`std::vector`
>> inheritance" yields many results of users trying to maintain the
>> original
>> interface and functionality but add one or two methods.
>>
>> The functionality should have the following requirements:
>>
>> - Can be applied to existing code.
>> - Should limit dependencies between new and old type as much as possible=
..
>> - Should allow for partial extensions of the old code.
>>
>> Alternatives
>> ------------
>>
>> ### Typedef / Using Directive ###
>>
>> Using a type alias creates an alternative name for a single type.
>> However, this
>> leaves no space to implement overloads that are context-specific. Nor a
>> type can
>> be extended in a simple way while keeping the old interface intact.
>>
>> ### Inheritance ###
>>
>> Inheritance requires redefinition of all constructors, and creates a
>> stricter
>> dependency between two classes than what is proposed here. Classes may b=
e
>> converted to a common ancestor even though that is undesired or even
>> dangerous
>> in case of implicit conversions.
>>
>> Inheritance may also be unwanted in order to avoid risks linked to
>> polymorphism
>> and freeing data structures where the base class does not have a virtual
>> destructor.
>>
>> ### Encapsulation with Manual Exposure of Needed Methods ###
>>
>> This method obviously requires a great deal of code to be rewritten in
>> order to
>> wrap every single method that the old class was exposing.
>>
>> In addition one needs to have intimate knowledge of the original
>> interface in
>> order to be able to duplicate it correctly. Template methods, rvalue
>> references,
>> possibly undocumented methods which are required in order to allow the
>> class to
>> behave in the same way as before. This heightens the bar significantly
>> for many
>> users, since they may not know correctly how to duplicate an interface
>> and how
>> to forward parameters to the old interface correctly.
>>
>> The new code also must be maintained in case the old interface changes.
>>
>> ### Copying the Base Class ###
>>
>> This can be useful, but requires all code to be duplicated, and thus
>> significantly increases the burden of maintaining the code. All bugs
>> discovered
>> in one class must be fixed in the other class too. All new features
>> applied to
>> one class must be applied to the other too.
>>
>> ### Macro-expansion ###
>>
>> Macro expansions can be used in order to encode the interface and
>> implementation
>> of a given class just one time, and used multiple times to produce
>> separate
>> classes.
>>
>> This approach is unfortunately not applicable to existing code, and is
>> very hard
>> to extend if one wants to copy a class but add additional functionality
>> to it.
>>
>> ### Templates ###
>>
>> Templates produce for each instantiation a separate type. They are
>> unfortunately
>> not applicable to previously existing code. For new code, they would
>> require the
>> creation of "fake" template parameters that would need to vary in order =
to
>> produce separate types.
>>
>> In addition, class extension through templates is not possible:
>> variations would
>> need to be made through specialization, which itself requires copying
>> existing
>> code.
>>
>> Previous Work
>> -------------
>>
>> Strong typedefs have already been proposed for the C++ language multiple
>> times
>> ([N1706](
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf),
>> [N1891](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pd=
f
>> ),
>> [N3515](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pd=
f
>> ),
>> [N3741](https://isocpp.org/files/papers/n3741.pdf)). These typedefs are
>> named
>> *opaque typedefs*, and these papers try to explore and define exactly th=
e
>> behavior that such typedefs should and would have when used to create ne=
w
>> types. In particular, the keywords `public`, `protected` and `private`
>> are used
>> in order to create a specific relation with the original type and how is
>> the
>> new type allowed to be cast back to the original type or be used in its
>> place
>> during overloads.
>>
>> This document shares many of the the same principles, for example
>> (quoting from
>> N3741):
>>
>> > - Consistent with restrictions imposed on analogous relationships such
>> as
>> > base classes underlying derived classes and integer types underlying
>> enums,
>> > an underlying type should be (1) complete and (2) not cv-quali=EF=AC=
=81ed. We
>> also do
>> > not require that any enum type, reference type, array type, function
>> type, or
>> > pointer-to-member type be allowed as an underlying type.
>>
>> However, this document tries to propose a possibly more simple approach,
>> where
>> a new language feature is introduced with the same meaning and
>> functionality as
>> if the user autonomously implemented a new class him/herself, matching t=
he
>> original type completely. Thus, it should result for the user more simpl=
e
>> to
>> understand (as it simply matches already the already understood mechanic=
s
>> of
>> creating a new, unique type from nothing), and no new rules for type
>> conversion
>> and selection on overloads have to be created.
>>
>> Syntax
>> ------
>>
>> ### Simple Case ###
>>
>> Syntax could look something like this:
>>
>> ```cpp
>> class Base {
>> public:
>> Base() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> struct Copy : using Base {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> public:
>> Copy() : x(0) {}
>> void foo() { std::cout << "foo " << x << "\n"; }
>> private:
>> int x;
>> };
>>
>> */
>> ```
>>
>> One cannot copy a class and inherit at the same time. If such a class is
>> needed
>> one would need to create it by hand with the desided functionality and
>> inheriting from the desired classes, as it would be done normally.
>>
>> All method implementations would be the same. The copied class would
>> inherit
>> from the same classes its base class inherits from. All constructors
>> would work
>> in the same way.
>>
>> ### Adding New Functionality ###
>>
>> Ideally one could specify additional methods, separate from that of Base=
,
>> to add
>> upon the existing functionality.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> };
>>
>> struct Derived : public Base {};
>>
>> struct Copy : using Base {
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : using Derived {};
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct CopyDerived : public Base {};
>>
>> */
>> ```
>>
>> Only new methods need to be implemented for that class.
>>
>> #### Interfacing with the Original Class ####
>>
>> In order to interface with the original class, simple conversion
>> operators can
>> be added by the user explicitly at-will, in order to obtain the desired
>> interface. Note that if more types with this kind of compatibility were
>> needed,
>> one would only need to implement them once, since copying the produced
>> type
>> would copy the new, more compatible interface with it.
>>
>> ```cpp
>> struct Base {
>> public:
>> int x;
>>
>> private:
>> double y;
>> };
>>
>> struct Copy : using Base {
>> operator Base() { return Base{x, y}; }
>> };
>> ```
>>
>> `reinterpret_cast` may also be used to convert back to the original clas=
s,
>> limited by the tool's already existing rules.
>>
>> In general the usual rules of `reinterpret_cast` apply to the copied
>> classes
>> with respect to their general classes, exactly as if the copied class ha=
d
>> been
>> implemented by hand.
>>
>> ### Overloads ###
>>
>> Duplicating an existing class should allow for new overloads on the new
>> type,
>> and no ambiguity between the copied class, the old class and other copie=
d
>> classes.
>>
>> ```cpp
>> class Position : using std::pair<double, double> {};
>> class Distance : using std::pair<double, double> {};
>>
>> Position operator+(const Position & p, const Distance & d) {
>> return Position(p.first + d.first, p.second + d.second);
>> }
>>
>> Distance operator+(const Distance & lhs, const Distance & rhs) {
>> return Distance(lhs.first + rhs.first, lhs.second + rhs.second);
>> }
>>
>> // ...
>>
>> Position p(1, 1);
>> Distance d(1, 1);
>>
>> p + d; // OK
>> d + d; // OK
>> p + p; // Error
>> ```
>>
>> ### Templated Class Copy ###
>>
>> The user might want to create a single templatized copy interface, and
>> use it
>> multiple times. For example, one might want multiple copied classes whic=
h
>> can
>> convert to their original. This could be done as follows:
>>
>> ```cpp
>> struct A { int x; };
>>
>> template <typename T>
>> struct TemplatizedCopy : using T {
>> static_assert(std::is_standard_layout<T>::value,
>> "Can't use this with a non-standard-layout class");
>>
>> operator T&() { return *reinterpret_cast<T*>(this); }
>> };
>>
>> // Could be used either via normal typedefs
>> using Copy1 =3D TemplatizedCopy<A>;
>>
>> // Or via copy, depending on requirements.
>> struct Copy2 : using TemplatizedCopy<A> {};
>> ```
>>
>> ### Copying Template Classes ###
>>
>> Since the construct is similar to inheritance, the syntax for creating
>> aliases
>> of templated classes could be the same:
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T> {};
>>
>> B<int> b;
>> ```
>>
>> The copied class must have the same number or less of template parameter=
s
>> than
>> the base class. Partial or full specializations of the base class can be
>> allowed:
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A {};
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> B<int> b;
>> ```
>>
>> When the base class has partial specializations, only those who apply ar=
e
>> copied
>> to the copied class.
>>
>> ```cpp
>> template <typename T, typename U>
>> struct A { T t; U u; };
>>
>> template <typename U>
>> struct A<double, U> { double y; U u; };
>>
>> template <typename T>
>> struct A<T, int> { T t; char z; };
>>
>> template <typename T>
>> struct B : using A<T, double> {};
>>
>> /* Equivalent to
>>
>> template <typename T>
>> struct B { T t; double u; };
>>
>> template <>
>> struct B<double> { double y; double u; };
>>
>> */
>> ```
>>
>> The copied class can add additional specializations. Or specializations
>> for a
>> given class can copy another.
>>
>> ```cpp
>> template <typename T>
>> struct A { int x; };
>>
>> struct B { char c; };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> template <>
>> struct C<double> : using B {};
>>
>> template <>
>> struct A<int> : using C<double> {};
>>
>> /* Equivalent to
>>
>> template<>
>> struct A<int> { char c; };
>>
>> template <typename T>
>> struct C { int x; };
>>
>> template <>
>> struct C<double> { char c; };
>>
>> */
>> ```
>>
>> ### Copying Multiple Dependent Classes ###
>>
>> Copying multiple classes using the simple syntax we have described can b=
e
>> impossible if those classes depend on one another. This is because each
>> copy
>> would depend on the originals, rather than on the copied classes. A
>> possible way
>> to specify such dependencies could be:
>>
>> ```cpp
>> struct A;
>>
>> struct B {
>> A * a;
>> };
>>
>> struct A {
>> B b;
>> };
>>
>> struct C;
>>
>> struct D : using B {
>> using class C =3D A;
>> };
>>
>> struct C : using A {
>> using class D =3D B;
>> };
>>
>> /* Equivalent to
>>
>> struct C;
>>
>> struct D {
>> C * a;
>> };
>>
>> struct C {
>> D b;
>> };
>>
>> */
>> ```
>>
>> `using class` has been used in order to disambiguate it from normal
>> `using`
>> alias directive. `using class` is only valid when the left hand side has
>> been
>> defined as a copy of the right hand side.
>>
>> In case of a template base class using a template second class, one coul=
d
>> specify different copies for certain specializations;
>>
>> ```cpp
>> template <typename T>
>> struct A {};
>>
>> template <typename T>
>> struct B {
>> A<T> a;
>> };
>>
>> template <typename T>
>> struct C : using A<T> {};
>>
>> ```
>>
>> ### Substituting Existing Functionality (Optional) ###
>>
>> Ideally one may want to use most of an implementation for another class,
>> but
>> vary a certain number of methods. In this case, if `Copy` contains a
>> member
>> function that already exists in `Base`, then that implementation is
>> substituted
>> in `Copy`. This may or may not be allowed for attributes.
>>
>> ```cpp
>> struct Base {
>> void foo() { std::cout << "foo\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> struct Copy : using Base {
>> void foo() { std::cout << "baz\n"; }
>> };
>>
>> /* Equivalent to
>>
>> struct Copy {
>> void foo() { std::cout << "baz\n"; }
>> void bar() { std::cout << "bar\n"; }
>> };
>>
>> */
>> ```
>>
>> A side effect of this is that it could allow for some type of
>> "interface", where
>> some base class could be defined as:
>>
>> ```cpp
>> struct Base {
>> Base() =3D delete;
>> void foo();
>> void bar();
>> };
>>
>> struct Copy1 : using Base {
>> Copy1() =3D default;
>> void baz();
>> void foo() =3D delete;
>> };
>>
>> /* Equivalent to
>>
>> struct Copy1 {
>> Copy1() =3D default;
>> void bar();
>> void baz();
>> };
>>
>> */
>>
>> struct Copy2 : using Base {
>> Copy2(int);
>> void abc();
>> };
>>
>> /*
>>
>> Equivalent to
>>
>> struct Copy2 {
>> Copy2(int);
>> void foo();
>> void bar();
>> void abc();
>> };
>>
>> */
>> ```
>>
>> This feature could however present problems when the members changed als=
o
>> alter
>> behavior and/or variable types of non-modified member and non-member
>> functions,
>> since the new behavior could be either erroneous or ambiguous.
>>
>> ### Copying and Extending Primitive Types (Optional) ###
>>
>> The same syntax could be used in order to extend primitive types. Using
>> the
>> extension that allows the modification of the copied types, this could
>> allow for
>> creation of numeric types where some operations are disabled as needed.
>>
>> ```cpp
>> struct Id : using int {
>> Id operator+(Id, Id) =3D delete;
>> Id operator*(Id, Id) =3D delete;
>> // Non-explicitly deleted operators keep their validity
>>
>> // Defining new operators with the old type can allow interoperativi=
ty
>> Id operator+(Id, int);
>> // We can convert the copied type to the old one.
>> operator int() { return (*this) * 2; }
>> };
>>
>> /* Equivalent to
>>
>> class Id final {
>> public:
>> Id operator/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }
>> Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs.v_}; }
>>
>> Id operator+(Id, int);
>> operator int() { return v_ * 2; }
>> private:
>> int v_;
>> };
>>
>> */
>> ```
>>
>> Note that when copying from a primitive types inheritance is forbidden a=
s
>> the
>> generated copy is `final` (although it is allowed to keep copying the
>> newly
>> created class).
>>
>> ### STL Traits (Optional) ###
>>
>> Traits could be included in the standard library in order to determine
>> whether a
>> class is a copy of another, or if it has been derived from a copy
>> (copies/inheritances could be nested arbitrarily).
>>
>> ```cpp
>> struct Base {};
>>
>> struct Copy : using Base {};
>>
>> static_assert(std::is_copy<Copy, Base>::value);
>>
>> struct ChildCopy : public Copy {};
>>
>> struct CopyChildCopy : using ChildCopy {};
>>
>> static_assert(std::is_copy_base_of<Base, CopyChildCopy>::value);
>> ```
>>
>> Compatibility
>> -------------
>>
>> As the syntax is new, no old code would be affected.
>>
>> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6718363e-351=
7-4af2-aa5f-9f0dd436c14b%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6718363e-35=
17-4af2-aa5f-9f0dd436c14b%40isocpp.org?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAPCFJdRs8f_p1oG-gyyL7-sD1GOdWCZHaAULknOghsdwLZd=
MDg%40mail.gmail.com.
--94eb2c0ada6eff79ee0554bc5d59
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I don't think the syntax is the main problem of this p=
roposed direction; write a paper with semantics described and publish it in=
a mailing.</div><br><div class=3D"gmail_quote"><div dir=3D"ltr">On Thu, Ju=
l 20, 2017 at 11:25 AM Alex Newlifer <<a href=3D"mailto:alex.newlifer@gm=
ail.com">alex.newlifer@gmail.com</a>> wrote:<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr"><div>Hello!</div><div><br></div><div>I sugge=
st to use `explicit` specifier for using-declaration to make strong</div><d=
iv>typedef (aka completely new type).</div><div><br></div><div>Simple examp=
le:</div><div>```</div><div>using explicit my_int_t =3D int;</div><div><br>=
</div><div>/* Now we cannot pass into function foo int values without expli=
cit cast.</div><div>*/</div><div>void foo(my_int_t val)</div><div>{}</div><=
div><br></div><div>int val =3D 0;</div><div><br></div><div>foo(val); // Err=
or</div><div>foo(static_cast<my_int_t>(val)); // Ok</div><div>foo(my_=
int_t(0)); // Ok</div><div>```</div><div><br></div><br>=D0=BF=D0=BE=D0=BD=
=D0=B5=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA, 19 =D0=B4=D0=B5=D0=BA=D0=
=B0=D0=B1=D1=80=D1=8F 2016 =D0=B3., 14:04:48 UTC+3 =D0=BF=D0=BE=D0=BB=D1=8C=
=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C <a href=3D"mailto:sval...@=
gmail.com" target=3D"_blank">sval...@gmail.com</a> =D0=BD=D0=B0=D0=BF=D0=B8=
=D1=81=D0=B0=D0=BB:</div><div dir=3D"ltr"><blockquote class=3D"gmail_quote"=
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-lef=
t:1ex"><div dir=3D"ltr">This is a stub proposal on strong typedefs, i.e. ty=
pes that work in the exact same way, but allow separate overloading. Other =
papers and proposals exist, but I've tried a different approach that tr=
ies to mimic a more inheritance-like syntax which might be more intuitive. =
The full text can be found online at <a href=3D"https://github.com/Svalorze=
n/CppCopyProposal" rel=3D"nofollow" target=3D"_blank">https://github.com/Sv=
alorzen/CppCopyProposal.<br><br></a>I'm copying the text below. Thanks =
in advance for your comments.<br><br><span style=3D"font-family:courier new=
,monospace">Duplication and Extension of Existing Classes<br>=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>Introduction<br>---=
---------<br><br>This document describes a possible approach to duplicate e=
xisting functionality<br>while wrapping it in a new type, without the burde=
n of inheritance and to allow<br>function overloads on syntactically identi=
cal but semantically different types<br>(also known as *strong typedef*).<b=
r><br>The approach taken should be simple to implement and be applicable to=
existing<br>code.<br><br>Optional sections are to be read as additional id=
eas that could be further<br>developed or completely ignored. They are most=
ly food for thought, but included<br>for completeness.<br><br>Reasons<br>--=
-----<br><br>- Scientific libraries where a type has different behaviors de=
pending on context<br>=C2=A0 have currently no simple way to indicate the s=
emantic differences. Since a<br>=C2=A0 `typedef` does not allow multiple ov=
erloads on new typedef types - since they<br>=C2=A0 are still the "old=
" type - they have to resort to imperfect techniques, such<br>=C2=A0 a=
s copying, wrapping or inheriting the needed type. Examples: coordinates in=
a<br>=C2=A0 plane (rectangular, polar), vectors of double (probabilities, =
values).<br>- Easier maintainability of code which is known to be the same,=
rather than<br>=C2=A0 being copy-pasted.<br>- Avoiding misuse of inheritan=
ce in order to provide a copy-paste alternative.<br>=C2=A0 This can result =
in very deep hierarchies of types which should really not have<br>=C2=A0 an=
ything to do with each other.<br>- Enabling users to use an existing and pr=
esumably correct type but partially<br>=C2=A0 extend it with context-specif=
ic methods. Examples: search for "`std::vector`<br>=C2=A0 inheritance&=
quot; yields many results of users trying to maintain the original<br>=C2=
=A0 interface and functionality but add one or two methods.<br><br>The func=
tionality should have the following requirements:<br><br>- Can be applied t=
o existing code.<br>- Should limit dependencies between new and old type as=
much as possible.<br>- Should allow for partial extensions of the old code=
..<br><br>Alternatives<br>------------<br><br>### Typedef / Using Directive =
###<br><br>Using a type alias creates an alternative name for a single type=
.. However, this<br>leaves no space to implement overloads that are context-=
specific. Nor a type can<br>be extended in a simple way while keeping the o=
ld interface intact.<br><br>### Inheritance ###<br><br>Inheritance requires=
redefinition of all constructors, and creates a stricter<br>dependency bet=
ween two classes than what is proposed here. Classes may be<br>converted to=
a common ancestor even though that is undesired or even dangerous<br>in ca=
se of implicit conversions.<br><br>Inheritance may also be unwanted in orde=
r to avoid risks linked to polymorphism<br>and freeing data structures wher=
e the base class does not have a virtual<br>destructor.<br><br>### Encapsul=
ation with Manual Exposure of Needed Methods ###<br><br>This method obvious=
ly requires a great deal of code to be rewritten in order to<br>wrap every =
single method that the old class was exposing.<br><br>In addition one needs=
to have intimate knowledge of the original interface in<br>order to be abl=
e to duplicate it correctly. Template methods, rvalue references,<br>possib=
ly undocumented methods which are required in order to allow the class to<b=
r>behave in the same way as before. This heightens the bar significantly fo=
r many<br>users, since they may not know correctly how to duplicate an inte=
rface and how<br>to forward parameters to the old interface correctly.<br><=
br>The new code also must be maintained in case the old interface changes.<=
br><br>### Copying the Base Class ###<br><br>This can be useful, but requir=
es all code to be duplicated, and thus<br>significantly increases the burde=
n of maintaining the code. All bugs discovered<br>in one class must be fixe=
d in the other class too. All new features applied to<br>one class must be =
applied to the other too.<br><br>### Macro-expansion ###<br><br>Macro expan=
sions can be used in order to encode the interface and implementation<br>of=
a given class just one time, and used multiple times to produce separate<b=
r>classes.<br><br>This approach is unfortunately not applicable to existing=
code, and is very hard<br>to extend if one wants to copy a class but add a=
dditional functionality to it.<br><br>### Templates ###<br><br>Templates pr=
oduce for each instantiation a separate type. They are unfortunately<br>not=
applicable to previously existing code. For new code, they would require t=
he<br>creation of "fake" template parameters that would need to v=
ary in order to<br>produce separate types.<br><br>In addition, class extens=
ion through templates is not possible: variations would<br>need to be made =
through specialization, which itself requires copying existing<br>code.<br>=
<br>Previous Work<br>-------------<br><br>Strong typedefs have already been=
proposed for the C++ language multiple times<br>([N1706](<a href=3D"http:/=
/www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf" rel=3D"nofollo=
w" target=3D"_blank">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/200=
4/n1706.pdf</a>),<br>[N1891](<a href=3D"http://www.open-std.org/jtc1/sc22/w=
g21/docs/papers/2005/n1891.pdf" rel=3D"nofollow" target=3D"_blank">http://w=
ww.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf</a>),<br>[N3515](=
<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pd=
f" rel=3D"nofollow" target=3D"_blank">http://www.open-std.org/jtc1/sc22/wg2=
1/docs/papers/2013/n3515.pdf</a>),<br>[N3741](<a href=3D"https://isocpp.org=
/files/papers/n3741.pdf)" rel=3D"nofollow" target=3D"_blank">https://isocpp=
..org/files/papers/n3741.pdf)</a>). These typedefs are named<br>*opaque type=
defs*, and these papers try to explore and define exactly the<br>behavior t=
hat such typedefs should and would have when used to create new<br>types. I=
n particular, the keywords `public`, `protected` and `private` are used<br>=
in order to create a specific relation with the original type and how is th=
e<br>new type allowed to be cast back to the original type or be used in it=
s place<br>during overloads.<br><br>This document shares many of the the sa=
me principles, for example (quoting from<br>N3741):<br><br>> - Consisten=
t with restrictions imposed on analogous relationships such as<br>>=C2=
=A0=C2=A0 base classes underlying derived classes and integer types underly=
ing enums,<br>>=C2=A0=C2=A0 an underlying type should be (1) complete an=
d (2) not cv-quali=EF=AC=81ed. We also do<br>>=C2=A0=C2=A0 not require t=
hat any enum type, reference type, array type, function type, or<br>>=C2=
=A0=C2=A0 pointer-to-member type be allowed as an underlying type.<br><br>H=
owever, this document tries to propose a possibly more simple approach, whe=
re<br>a new language feature is introduced with the same meaning and functi=
onality as<br>if the user autonomously implemented a new class him/herself,=
matching the<br>original type completely. Thus, it should result for the u=
ser more simple to<br>understand (as it simply matches already the already =
understood mechanics of<br>creating a new, unique type from nothing), and n=
o new rules for type conversion<br>and selection on overloads have to be cr=
eated.<br><br>Syntax<br>------<br><br>### Simple Case ###<br><br>Syntax cou=
ld look something like this:<br><br>```cpp<br>class Base {<br>=C2=A0=C2=A0=
=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Base() : x(0) =
{}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo() { std::cout <=
;< "foo " << x << "\n"; }<br>=C2=A0=C2=
=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int x;<br>=
};<br><br>struct Copy : using Base {};<br><br>/* Equivalent to<br><br>struc=
t Copy {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 Copy() : x(0) {}<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 vo=
id foo() { std::cout << "foo " << x << "\n=
"; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 int x;<br>};<br><br>*/<br>```<br><br>One cannot copy a class a=
nd inherit at the same time. If such a class is needed<br>one would need to=
create it by hand with the desided functionality and<br>inheriting from th=
e desired classes, as it would be done normally.<br><br>All method implemen=
tations would be the same. The copied class would inherit<br>from the same =
classes its base class inherits from. All constructors would work<br>in the=
same way.<br><br>### Adding New Functionality ###<br><br>Ideally one could=
specify additional methods, separate from that of Base, to add<br>upon the=
existing functionality.<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=C2=
=A0 void foo() { std::cout << "foo\n"; }<br>};<br><br>struc=
t Derived : public Base {};<br><br>struct Copy : using Base {<br>=C2=A0=C2=
=A0=C2=A0 void bar() { std::cout << "bar\n"; }<br>};<br><br=
>struct CopyDerived : using Derived {};<br><br>/* Equivalent to<br><br>stru=
ct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n=
"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n=
"; }<br>};<br><br>struct CopyDerived : public Base {};<br><br>*/<br>``=
`<br><br>Only new methods need to be implemented for that class.<br><br>###=
# Interfacing with the Original Class ####<br><br>In order to interface wit=
h the original class, simple conversion operators can<br>be added by the us=
er explicitly at-will, in order to obtain the desired<br>interface. Note th=
at if more types with this kind of compatibility were needed,<br>one would =
only need to implement them once, since copying the produced type<br>would =
copy the new, more compatible interface with it.<br><br>```cpp<br>struct Ba=
se {<br>=C2=A0=C2=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 int x;<br><br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 double y;<br>};<br><br>struct Copy : using Base {<br>=
=C2=A0=C2=A0=C2=A0 operator Base() { return Base{x, y}; }<br>};<br>```<br><=
br>`reinterpret_cast` may also be used to convert back to the original clas=
s,<br>limited by the tool's already existing rules.<br><br>In general t=
he usual rules of `reinterpret_cast` apply to the copied classes<br>with re=
spect to their general classes, exactly as if the copied class had been<br>=
implemented by hand.<br><br>### Overloads ###<br><br>Duplicating an existin=
g class should allow for new overloads on the new type,<br>and no ambiguity=
between the copied class, the old class and other copied<br>classes.<br><b=
r>```cpp<br>class Position : using std::pair<double, double> {};<br>c=
lass Distance : using std::pair<double, double> {};<br><br>Position o=
perator+(const Position & p, const Distance & d) {<br>=C2=A0=C2=A0=
=C2=A0 return Position(p.first + d.first, p.second + d.second);<br>}<br><br=
>Distance operator+(const Distance & lhs, const Distance & rhs) {<b=
r>=C2=A0=C2=A0=C2=A0 return Distance(lhs.first + rhs.first, lhs.second + rh=
s.second);<br>}<br><br>// ...<br><br>Position p(1, 1);<br>Distance d(1, 1);=
<br><br>p + d; // OK<br>d + d; // OK<br>p + p; // Error<br>```<br><br>### T=
emplated Class Copy ###<br><br>The user might want to create a single templ=
atized copy interface, and use it<br>multiple times. For example, one might=
want multiple copied classes which can<br>convert to their original. This =
could be done as follows:<br><br>```cpp<br>struct A { int x; };<br><br>temp=
late <typename T><br>struct TemplatizedCopy : using T {<br>=C2=A0=C2=
=A0=C2=A0 static_assert(std::is_standard_layout<T>::value,<br>=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 "Can't use this with a non-standard-layout c=
lass");<br><br>=C2=A0=C2=A0=C2=A0 operator T&() { return *reinterp=
ret_cast<T*>(this); }<br>};<br><br>// Could be used either via normal=
typedefs<br>using Copy1 =3D TemplatizedCopy<A>;<br><br>// Or via cop=
y, depending on requirements.<br>struct Copy2 : using TemplatizedCopy<A&=
gt; {};<br>```<br><br>### Copying Template Classes ###<br><br>Since the con=
struct is similar to inheritance, the syntax for creating aliases<br>of tem=
plated classes could be the same:<br><br>```cpp<br>template <typename T&=
gt;<br>struct A {};<br><br>template <typename T><br>struct B : using =
A<T> {};<br><br>B<int> b;<br>```<br><br>The copied class must h=
ave the same number or less of template parameters than<br>the base class. =
Partial or full specializations of the base class can be allowed:<br><br>``=
`cpp<br>template <typename T, typename U><br>struct A {};<br><br>temp=
late <typename T><br>struct B : using A<T, double> {};<br><br>B=
<int> b;<br>```<br><br>When the base class has partial specialization=
s, only those who apply are copied<br>to the copied class.<br><br>```cpp<br=
>template <typename T, typename U><br>struct A { T t; U u; };<br><br>=
template <typename U><br>struct A<double, U> { double y; U u; }=
;<br><br>template <typename T><br>struct A<T, int> { T t; char =
z; };<br><br>template <typename T><br>struct B : using A<T, double=
> {};<br><br>/* Equivalent to<br><br>template <typename T><br>stru=
ct B { T t; double u; };<br><br>template <><br>struct B<double>=
{ double y; double u; };<br><br>*/<br>```<br><br>The copied class can add =
additional specializations. Or specializations for a<br>given class can cop=
y another.<br><br>```cpp<br>template <typename T><br>struct A { int x=
; };<br><br>struct B { char c; };<br><br>template <typename T><br>str=
uct C : using A<T> {};<br><br>template <><br>struct C<double=
> : using B {};<br><br>template <><br>struct A<int> : using =
C<double> {};<br><br>/* Equivalent to<br><br>template<><br>stru=
ct A<int> { char c; };<br><br>template <typename T><br>struct C=
{ int x; };<br><br>template <><br>struct C<double> { char c; }=
;<br><br>*/<br>```<br><br>### Copying Multiple Dependent Classes ###<br><br=
>Copying multiple classes using the simple syntax we have described can be<=
br>impossible if those classes depend on one another. This is because each =
copy<br>would depend on the originals, rather than on the copied classes. A=
possible way<br>to specify such dependencies could be:<br><br>```cpp<br>st=
ruct A;<br><br>struct B {<br>=C2=A0=C2=A0=C2=A0 A * a;<br>};<br><br>struct =
A {<br>=C2=A0=C2=A0=C2=A0 B b;<br>};<br><br>struct C;<br><br>struct D : usi=
ng B {<br>=C2=A0=C2=A0=C2=A0 using class C =3D A;<br>};<br><br>struct C : u=
sing A {<br>=C2=A0=C2=A0=C2=A0 using class D =3D B;<br>};<br><br>/* Equival=
ent to<br><br>struct C;<br><br>struct D {<br>=C2=A0=C2=A0=C2=A0 C * a;<br>}=
;<br><br>struct C {<br>=C2=A0=C2=A0=C2=A0 D b;<br>};<br><br>*/<br>```<br><b=
r>`using class` has been used in order to disambiguate it from normal `usin=
g`<br>alias directive. `using class` is only valid when the left hand side =
has been<br>defined as a copy of the right hand side.<br><br>In case of a t=
emplate base class using a template second class, one could<br>specify diff=
erent copies for certain specializations;<br><br>```cpp<br>template <typ=
ename T><br>struct A {};<br><br>template <typename T><br>struct B =
{<br>=C2=A0=C2=A0=C2=A0 A<T> a;<br>};<br><br>template <typename T&=
gt;<br>struct C : using A<T> {};<br><br>```<br><br>### Substituting E=
xisting Functionality (Optional) ###<br><br>Ideally one may want to use mos=
t of an implementation for another class, but<br>vary a certain number of m=
ethods. In this case, if `Copy` contains a member<br>function that already =
exists in `Base`, then that implementation is substituted<br>in `Copy`. Thi=
s may or may not be allowed for attributes.<br><br>```cpp<br>struct Base {<=
br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "foo\n"; }<=
br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "bar\n"; }<=
br>};<br><br>struct Copy : using Base {<br>=C2=A0=C2=A0=C2=A0 void foo() { =
std::cout << "baz\n"; }<br>};<br><br>/* Equivalent to<br><b=
r>struct Copy {<br>=C2=A0=C2=A0=C2=A0 void foo() { std::cout << "=
;baz\n"; }<br>=C2=A0=C2=A0=C2=A0 void bar() { std::cout << "=
;bar\n"; }<br>};<br><br>*/<br>```<br><br>A side effect of this is that=
it could allow for some type of "interface", where<br>some base =
class could be defined as:<br><br>```cpp<br>struct Base {<br>=C2=A0=C2=A0=
=C2=A0 Base() =3D delete;<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=A0=C2=A0=
=C2=A0 void bar();<br>};<br><br>struct Copy1 : using Base {<br>=C2=A0=C2=A0=
=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 void baz();<br>=C2=A0=C2=
=A0=C2=A0 void foo() =3D delete;<br>};<br><br>/* Equivalent to<br><br>struc=
t Copy1 {<br>=C2=A0=C2=A0=C2=A0 Copy1() =3D default;<br>=C2=A0=C2=A0=C2=A0 =
void bar();<br>=C2=A0=C2=A0=C2=A0 void baz();<br>};<br><br>*/<br><br>struct=
Copy2 : using Base {<br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=
=A0 void abc();<br>};<br><br>/*<br><br>Equivalent to<br><br>struct Copy2 {<=
br>=C2=A0=C2=A0=C2=A0 Copy2(int);<br>=C2=A0=C2=A0=C2=A0 void foo();<br>=C2=
=A0=C2=A0=C2=A0 void bar();<br>=C2=A0=C2=A0=C2=A0 void abc();<br>};<br><br>=
*/<br>```<br><br>This feature could however present problems when the membe=
rs changed also alter<br>behavior and/or variable types of non-modified mem=
ber and non-member functions,<br>since the new behavior could be either err=
oneous or ambiguous.<br><br>### Copying and Extending Primitive Types (Opti=
onal) ###<br><br>The same syntax could be used in order to extend primitive=
types. Using the<br>extension that allows the modification of the copied t=
ypes, this could allow for<br>creation of numeric types where some operatio=
ns are disabled as needed.<br><br>```cpp<br>struct Id : using int {<br>=C2=
=A0=C2=A0=C2=A0 Id operator+(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 Id o=
perator*(Id, Id) =3D delete;<br>=C2=A0=C2=A0=C2=A0 // Non-explicitly delete=
d operators keep their validity<br><br>=C2=A0=C2=A0=C2=A0 // Defining new o=
perators with the old type can allow interoperativity<br>=C2=A0=C2=A0=C2=A0=
Id operator+(Id, int);<br>=C2=A0=C2=A0=C2=A0 // We can convert the copied =
type to the old one.<br>=C2=A0=C2=A0=C2=A0 operator int() { return (*this) =
* 2; }<br>};<br><br>/* Equivalent to<br><br>class Id final {<br>=C2=A0=C2=
=A0=C2=A0 public:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator=
/(Id lhs, Id rhs) { return Id{lhs.v_ / rhs.v_}; }<br>=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 Id operator-(Id lhs, Id rhs) { return Id{lhs.v_ - rhs=
..v_}; }<br><br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Id operator+(Id, =
int);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 operator int() { return=
v_ * 2; }<br>=C2=A0=C2=A0=C2=A0 private:<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 int v_;<br>};<br><br>*/<br>```<br><br>Note that when copying f=
rom a primitive types inheritance is forbidden as the<br>generated copy is =
`final` (although it is allowed to keep copying the newly<br>created class)=
..<br><br>### STL Traits (Optional) ###<br><br>Traits could be included in t=
he standard library in order to determine whether a<br>class is a copy of a=
nother, or if it has been derived from a copy<br>(copies/inheritances could=
be nested arbitrarily).<br><br>```cpp<br>struct Base {};<br><br>struct Cop=
y : using Base {};<br><br>static_assert(std::is_copy<Copy, Base>::val=
ue);<br><br>struct ChildCopy : public Copy {};<br><br>struct CopyChildCopy =
: using ChildCopy {};<br><br>static_assert(std::is_copy_base_of<Base, Co=
pyChildCopy>::value);<br>```<br><br>Compatibility<br>-------------<br><b=
r>As the syntax is new, no old code would be affected.<br></span><br></div>=
</blockquote></div>
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6718363e-3517-4af2-aa5f-9f0dd436c14b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6718363e-3517-=
4af2-aa5f-9f0dd436c14b%40isocpp.org</a>.<br>
</blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAPCFJdRs8f_p1oG-gyyL7-sD1GOdWCZHaAUL=
knOghsdwLZdMDg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAPCFJdRs8f_p1oG-=
gyyL7-sD1GOdWCZHaAULknOghsdwLZdMDg%40mail.gmail.com</a>.<br />
--94eb2c0ada6eff79ee0554bc5d59--
.
Author: =?UTF-8?Q?Jonathan_M=c3=bcller?= <jonathanmueller.dev@gmail.com>
Date: Thu, 20 Jul 2017 11:29:40 +0200
Raw View
On 20.07.2017 11:25, Alex Newlifer wrote:
> Hello!
>
> I suggest to use `explicit` specifier for using-declaration to make strong
> typedef (aka completely new type).
>
> Simple example:
> ```
> using explicit my_int_t = int;
>
> /* Now we cannot pass into function foo int values without explicit cast.
> */
> void foo(my_int_t val)
> {}
>
> int val = 0;
>
> foo(val); // Error
> foo(static_cast<my_int_t>(val)); // Ok
> foo(my_int_t(0)); // Ok
> ```
>
While this would be a great step forward, this is not useful for all cases.
In a strong typedef you'd want to keep certain functions like an
`operator+` in your example, but not necessarily *all* operators, member
functions.
See my blog post about it for rationale:
http://foonathan.net/blog/2016/10/19/strong-typedefs.html
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%40gmail.com.
.
Author: John McFarlane <john@mcfarlane.name>
Date: Thu, 20 Jul 2017 10:59:28 +0000
Raw View
--001a11476f9c2d71db0554bda569
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Thu, Jul 20, 2017 at 2:29 AM Jonathan M=C3=BCller <
jonathanmueller.dev@gmail.com> wrote:
> On 20.07.2017 11:25, Alex Newlifer wrote:
> > Hello!
> >
> > I suggest to use `explicit` specifier for using-declaration to make
> strong
> > typedef (aka completely new type).
> >
> > Simple example:
> > ```
> > using explicit my_int_t =3D int;
> >
> > /* Now we cannot pass into function foo int values without explicit cas=
t.
> > */
> > void foo(my_int_t val)
> > {}
> >
> > int val =3D 0;
> >
> > foo(val); // Error
> > foo(static_cast<my_int_t>(val)); // Ok
> > foo(my_int_t(0)); // Ok
> > ```
> >
>
> While this would be a great step forward, this is not useful for all case=
s.
>
Yes, something like this could be helpful for improving type safety.
In a strong typedef you'd want to keep certain functions like an
> `operator+` in your example, but not necessarily *all* operators, member
> functions.
>
Perhaps removing the operators of a type should be separated from the
concern of removing implicit casting. If you don't want the full
complement of arithmetic, maybe you should not start with `int` at all, but
instead 'explicitly alias' a type with only the operators you want.
(Something like `boost::operators` can make this a easier to achieve.)
John
>
> See my blog post about it for rationale:
> http://foonathan.net/blog/2016/10/19/strong-typedefs.html
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4=
c-4b1e-6e29-477a9cb3a66d%40gmail.com
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-oLZBStoAmSjODiCAeq9MzDooq%2BTkz=
sV9sA%40mail.gmail.com.
--001a11476f9c2d71db0554bda569
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_quote"><div dir=3D"ltr">On Thu, Jul 20=
, 2017 at 2:29 AM Jonathan M=C3=BCller <<a href=3D"mailto:jonathanmuelle=
r.dev@gmail.com">jonathanmueller.dev@gmail.com</a>> wrote:<br></div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #c=
cc solid;padding-left:1ex">On 20.07.2017 11:25, Alex Newlifer wrote:<br>
> Hello!<br>
><br>
> I suggest to use `explicit` specifier for using-declaration to make st=
rong<br>
> typedef (aka completely new type).<br>
><br>
> Simple example:<br>
> ```<br>
> using explicit my_int_t =3D int;<br>
><br>
> /* Now we cannot pass into function foo int values without explicit ca=
st.<br>
> */<br>
> void foo(my_int_t val)<br>
> {}<br>
><br>
> int val =3D 0;<br>
><br>
> foo(val); // Error<br>
> foo(static_cast<my_int_t>(val)); // Ok<br>
> foo(my_int_t(0)); // Ok<br>
> ```<br>
><br>
<br>
While this would be a great step forward, this is not useful for all cases.=
<br></blockquote><div><br></div><div>Yes, something like this could be help=
ful for improving type safety.<br><br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In a strong typedef you'd want to keep certain functions like an<br>
`operator+` in your example, but not necessarily *all* operators, member<br=
>
functions.<br></blockquote><div><br></div><div>Perhaps removing the operato=
rs of a type should be separated from the concern of removing implicit cast=
ing.=C2=A0 If you don't want the full complement of arithmetic, maybe y=
ou should not start with `int` at all, but instead 'explicitly alias=
9; a type with only the operators you want.=C2=A0 (Something like `boost::o=
perators` can make this a easier to achieve.)=C2=A0 <br><br></div><div>John=
<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex">
<br>
See my blog post about it for rationale:<br>
<a href=3D"http://foonathan.net/blog/2016/10/19/strong-typedefs.html" rel=
=3D"noreferrer" target=3D"_blank">http://foonathan.net/blog/2016/10/19/stro=
ng-typedefs.html</a><br>
<br>
--<br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%=
40gmail.com" rel=3D"noreferrer" target=3D"_blank">https://groups.google.com=
/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%40=
gmail.com</a>.<br>
</blockquote></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-oLZBStoAmSjODiCAeq9M=
zDooq%2BTkzsV9sA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3=
c-oLZBStoAmSjODiCAeq9MzDooq%2BTkzsV9sA%40mail.gmail.com</a>.<br />
--001a11476f9c2d71db0554bda569--
.
Author: drozdovkonstantin@gmail.com
Date: Thu, 20 Jul 2017 05:37:02 -0700 (PDT)
Raw View
------=_Part_470_504483164.1500554222134
Content-Type: multipart/alternative;
boundary="----=_Part_471_232891659.1500554222134"
------=_Part_471_232891659.1500554222134
Content-Type: text/plain; charset="UTF-8"
Here is some ideas:
1. Strong typedefs are declared by 'using explicit alias_type = type'.
2. Strong typedefs can not be implicitly casted but can be explicitly
casted.
3. Strong typedefs are different types by mean of template arguments.
4. Strong typedefs are guaranteed to be exactly the same in-memory and are
exactly the same type by mean of RTTI (this requires some review over
std::variant and other typeinfo-dependent templates).
5. Strong typedefs has helper code like
namespace std {
template <typename T1, typename T2>
enable_if<is_strong_alias<T1, T2>::value, T1&>::type explicit_cast(T2 &
ref) { return static_cast<T1&>(ref); };
//...
}
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6d94a661-4729-41d8-8293-0e0f22e5b10f%40isocpp.org.
------=_Part_471_232891659.1500554222134
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Here is some ideas:<br><br>1. Strong typedefs are declared=
by 'using explicit alias_type =3D type'.<br>2. Strong typedefs can=
not be implicitly casted but can be explicitly casted.<br>3. Strong typede=
fs are different types by mean of template arguments.<br>4. Strong typedefs=
are guaranteed to be exactly the same in-memory and are exactly the same t=
ype by mean of RTTI (this requires some review over std::variant and other =
typeinfo-dependent templates).<br>5. Strong typedefs has helper code like <=
br><br>namespace std {<br>=C2=A0=C2=A0 template <typename T1, typename T=
2><br>=C2=A0=C2=A0 enable_if<is_strong_alias<T1, T2>::value, T1=
&>::type explicit_cast(T2 & ref) { return static_cast<T1&=
>(ref); };<br>=C2=A0=C2=A0 //...<br>}<br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6d94a661-4729-41d8-8293-0e0f22e5b10f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6d94a661-4729-41d8-8293-0e0f22e5b10f=
%40isocpp.org</a>.<br />
------=_Part_471_232891659.1500554222134--
------=_Part_470_504483164.1500554222134--
.
Author: drozdovkonstantin@gmail.com
Date: Thu, 20 Jul 2017 05:56:14 -0700 (PDT)
Raw View
------=_Part_474_619767638.1500555374956
Content-Type: multipart/alternative;
boundary="----=_Part_475_1530628136.1500555374956"
------=_Part_475_1530628136.1500555374956
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Basically with 'using explicit' syntax we want to declare exactly the same=
=20
runtime type without any operators or functions being modified with an=20
exception that every use of self type will be treated as a use of the=20
alias_type.=20
Basically this is something like declaring the original type as a template=
=20
with typename Scope that is never used in class declaration and ignored by=
=20
RTTI.
On Thursday, 20 July 2017 14:59:43 UTC+4, John McFarlane wrote:
>
> On Thu, Jul 20, 2017 at 2:29 AM Jonathan M=C3=BCller <jonathanm...@gmail.=
com=20
> <javascript:>> wrote:
>
>> On 20.07.2017 11:25, Alex Newlifer wrote:
>> > Hello!
>> >
>> > I suggest to use `explicit` specifier for using-declaration to make=20
>> strong
>> > typedef (aka completely new type).
>> >
>> > Simple example:
>> > ```
>> > using explicit my_int_t =3D int;
>> >
>> > /* Now we cannot pass into function foo int values without explicit=20
>> cast.
>> > */
>> > void foo(my_int_t val)
>> > {}
>> >
>> > int val =3D 0;
>> >
>> > foo(val); // Error
>> > foo(static_cast<my_int_t>(val)); // Ok
>> > foo(my_int_t(0)); // Ok
>> > ```
>> >
>>
>> While this would be a great step forward, this is not useful for all=20
>> cases.
>>
>
> Yes, something like this could be helpful for improving type safety.
>
> In a strong typedef you'd want to keep certain functions like an
>> `operator+` in your example, but not necessarily *all* operators, member
>> functions.
>>
>
> Perhaps removing the operators of a type should be separated from the=20
> concern of removing implicit casting. If you don't want the full=20
> complement of arithmetic, maybe you should not start with `int` at all, b=
ut=20
> instead 'explicitly alias' a type with only the operators you want. =20
> (Something like `boost::operators` can make this a easier to achieve.) =
=20
>
> John=20
>
>>
>> See my blog post about it for rationale:
>> http://foonathan.net/blog/2016/10/19/strong-typedefs.html
>>
>> --
>> You received this message because you are subscribed to the Google Group=
s=20
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n=20
>> email to std-proposal...@isocpp.org <javascript:>.
>> To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>> To view this discussion on the web visit=20
>> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f=
4c-4b1e-6e29-477a9cb3a66d%40gmail.com
>> .
>>
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/e133e4b0-f9eb-4e03-bc84-aaf28fd19441%40isocpp.or=
g.
------=_Part_475_1530628136.1500555374956
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Basically with 'using explicit' syntax we want to =
declare exactly the same runtime type without any operators or functions be=
ing modified with an exception that every use of self type will be treated =
as a use of the alias_type. <br><br>Basically this is something like declar=
ing the original type as a template with typename Scope that is never used =
in class declaration and ignored by RTTI.<br><br>On Thursday, 20 July 2017 =
14:59:43 UTC+4, John McFarlane wrote:<blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;"><div dir=3D"ltr"><div class=3D"gmail_quote"><div dir=3D"ltr">On Thu=
, Jul 20, 2017 at 2:29 AM Jonathan M=C3=BCller <<a href=3D"javascript:" =
target=3D"_blank" gdf-obfuscated-mailto=3D"6n-UNFs1AwAJ" rel=3D"nofollow" o=
nmousedown=3D"this.href=3D'javascript:';return true;" onclick=3D"th=
is.href=3D'javascript:';return true;">jonathanm...@gmail.com</a><wb=
r>> wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 =
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 20.07.2017 11:25, =
Alex Newlifer wrote:<br>
> Hello!<br>
><br>
> I suggest to use `explicit` specifier for using-declaration to make st=
rong<br>
> typedef (aka completely new type).<br>
><br>
> Simple example:<br>
> ```<br>
> using explicit my_int_t =3D int;<br>
><br>
> /* Now we cannot pass into function foo int values without explicit ca=
st.<br>
> */<br>
> void foo(my_int_t val)<br>
> {}<br>
><br>
> int val =3D 0;<br>
><br>
> foo(val); // Error<br>
> foo(static_cast<my_int_t>(val)<wbr>); // Ok<br>
> foo(my_int_t(0)); // Ok<br>
> ```<br>
><br>
<br>
While this would be a great step forward, this is not useful for all cases.=
<br></blockquote><div><br></div><div>Yes, something like this could be help=
ful for improving type safety.<br><br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In a strong typedef you'd want to keep certain functions like an<br>
`operator+` in your example, but not necessarily *all* operators, member<br=
>
functions.<br></blockquote><div><br></div><div>Perhaps removing the operato=
rs of a type should be separated from the concern of removing implicit cast=
ing.=C2=A0 If you don't want the full complement of arithmetic, maybe y=
ou should not start with `int` at all, but instead 'explicitly alias=
9; a type with only the operators you want.=C2=A0 (Something like `boost::o=
perators` can make this a easier to achieve.)=C2=A0 <br><br></div><div>John=
<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex">
<br>
See my blog post about it for rationale:<br>
<a href=3D"http://foonathan.net/blog/2016/10/19/strong-typedefs.html" rel=
=3D"nofollow" target=3D"_blank" onmousedown=3D"this.href=3D'http://www.=
google.com/url?q\x3dhttp%3A%2F%2Ffoonathan.net%2Fblog%2F2016%2F10%2F19%2Fst=
rong-typedefs.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFxWKpPBUgQ4YnKhz=
M-6OveyZb6lw';return true;" onclick=3D"this.href=3D'http://www.goog=
le.com/url?q\x3dhttp%3A%2F%2Ffoonathan.net%2Fblog%2F2016%2F10%2F19%2Fstrong=
-typedefs.html\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFxWKpPBUgQ4YnKhzM-6O=
veyZb6lw';return true;">http://foonathan.net/blog/<wbr>2016/10/19/stron=
g-typedefs.<wbr>html</a><br>
<br>
--<br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
6n-UNFs1AwAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D'javascript:&=
#39;;return true;" onclick=3D"this.href=3D'javascript:';return true=
;">std-proposal...@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"javascript:" target=3D"_bla=
nk" gdf-obfuscated-mailto=3D"6n-UNFs1AwAJ" rel=3D"nofollow" onmousedown=3D"=
this.href=3D'javascript:';return true;" onclick=3D"this.href=3D'=
;javascript:';return true;">std-pr...@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%=
40gmail.com" rel=3D"nofollow" target=3D"_blank" onmousedown=3D"this.href=3D=
'https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-=
2f4c-4b1e-6e29-477a9cb3a66d%40gmail.com';return true;" onclick=3D"this.=
href=3D'https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95=
d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%40gmail.com';return true;">https://g=
roups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/95d6f9b7-2f4c=
-4b1e-<wbr>6e29-477a9cb3a66d%40gmail.com</a>.<br>
</blockquote></div></div>
</blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/e133e4b0-f9eb-4e03-bc84-aaf28fd19441%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/e133e4b0-f9eb-4e03-bc84-aaf28fd19441=
%40isocpp.org</a>.<br />
------=_Part_475_1530628136.1500555374956--
------=_Part_474_619767638.1500555374956--
.
Author: Tony V E <tvaneerd@gmail.com>
Date: Thu, 20 Jul 2017 15:28:51 -0400
Raw View
--f403045ceeec36fdca0554c4c28d
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Here's some example code which may or may not be helped by some form of
"strong typedef".
https://github.com/tvaneerd/code/blob/master/StrongId.h
It wraps a string or int or whatever, and makes it a unique type (based on
a Tag template param).
Since it is for IDs, it doesn't want arithmetic (or concatenation)
operations, but it does want equality and less (et al).
I suspect you always want to "inherit" =3D=3D and !=3D, and most likely
relational ordering.
On Thu, Jul 20, 2017 at 6:59 AM, John McFarlane <john@mcfarlane.name> wrote=
:
> On Thu, Jul 20, 2017 at 2:29 AM Jonathan M=C3=BCller <
> jonathanmueller.dev@gmail.com> wrote:
>
>> On 20.07.2017 11:25, Alex Newlifer wrote:
>> > Hello!
>> >
>> > I suggest to use `explicit` specifier for using-declaration to make
>> strong
>> > typedef (aka completely new type).
>> >
>> > Simple example:
>> > ```
>> > using explicit my_int_t =3D int;
>> >
>> > /* Now we cannot pass into function foo int values without explicit
>> cast.
>> > */
>> > void foo(my_int_t val)
>> > {}
>> >
>> > int val =3D 0;
>> >
>> > foo(val); // Error
>> > foo(static_cast<my_int_t>(val)); // Ok
>> > foo(my_int_t(0)); // Ok
>> > ```
>> >
>>
>> While this would be a great step forward, this is not useful for all
>> cases.
>>
>
> Yes, something like this could be helpful for improving type safety.
>
> In a strong typedef you'd want to keep certain functions like an
>> `operator+` in your example, but not necessarily *all* operators, member
>> functions.
>>
>
> Perhaps removing the operators of a type should be separated from the
> concern of removing implicit casting. If you don't want the full
> complement of arithmetic, maybe you should not start with `int` at all, b=
ut
> instead 'explicitly alias' a type with only the operators you want.
> (Something like `boost::operators` can make this a easier to achieve.)
>
> John
>
>>
>> See my blog post about it for rationale:
>> http://foonathan.net/blog/2016/10/19/strong-typedefs.html
>>
>> --
>> You received this message because you are subscribed to the Google Group=
s
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n
>> email to std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/
>> isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-
>> 6e29-477a9cb3a66d%40gmail.com.
>>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-
> oLZBStoAmSjODiCAeq9MzDooq%2BTkzsV9sA%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1kz=
LAp3c-oLZBStoAmSjODiCAeq9MzDooq%2BTkzsV9sA%40mail.gmail.com?utm_medium=3Dem=
ail&utm_source=3Dfooter>
> .
>
--=20
Be seeing you,
Tony
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAOHCbit4n0oyoGp0ymu70APJg_UuNYyxd%2Bt1FQoU96DMm=
h8JKw%40mail.gmail.com.
--f403045ceeec36fdca0554c4c28d
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Here's some example code which may or may not be helpe=
d by some form of "strong typedef".<div><br></div><div><a href=3D=
"https://github.com/tvaneerd/code/blob/master/StrongId.h">https://github.co=
m/tvaneerd/code/blob/master/StrongId.h</a><br></div><div><br></div><div>It =
wraps a string or int or whatever, and makes it a unique type (based on a T=
ag template param).</div><div>Since it is for IDs, it doesn't want arit=
hmetic (or concatenation) operations, but it does want equality and less (e=
t al).</div><div><br></div><div>I suspect you always want to "inherit&=
quot; =3D=3D and !=3D, and most likely relational ordering.</div><div><br><=
/div></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Thu=
, Jul 20, 2017 at 6:59 AM, John McFarlane <span dir=3D"ltr"><<a href=3D"=
mailto:john@mcfarlane.name" target=3D"_blank">john@mcfarlane.name</a>></=
span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_quote"><span class=3D""><div dir=3D"ltr">On Thu, Jul 20, 2017 at =
2:29 AM Jonathan M=C3=BCller <<a href=3D"mailto:jonathanmueller.dev@gmai=
l.com" target=3D"_blank">jonathanmueller.dev@gmail.com</a><wbr>> wrote:<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;borde=
r-left:1px #ccc solid;padding-left:1ex">On 20.07.2017 11:25, Alex Newlifer =
wrote:<br>
> Hello!<br>
><br>
> I suggest to use `explicit` specifier for using-declaration to make st=
rong<br>
> typedef (aka completely new type).<br>
><br>
> Simple example:<br>
> ```<br>
> using explicit my_int_t =3D int;<br>
><br>
> /* Now we cannot pass into function foo int values without explicit ca=
st.<br>
> */<br>
> void foo(my_int_t val)<br>
> {}<br>
><br>
> int val =3D 0;<br>
><br>
> foo(val); // Error<br>
> foo(static_cast<my_int_t>(val)<wbr>); // Ok<br>
> foo(my_int_t(0)); // Ok<br>
> ```<br>
><br>
<br>
While this would be a great step forward, this is not useful for all cases.=
<br></blockquote><div><br></div></span><div>Yes, something like this could =
be helpful for improving type safety.<br><br></div><span class=3D""><blockq=
uote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc =
solid;padding-left:1ex">
In a strong typedef you'd want to keep certain functions like an<br>
`operator+` in your example, but not necessarily *all* operators, member<br=
>
functions.<br></blockquote><div><br></div></span><div>Perhaps removing the =
operators of a type should be separated from the concern of removing implic=
it casting.=C2=A0 If you don't want the full complement of arithmetic, =
maybe you should not start with `int` at all, but instead 'explicitly a=
lias' a type with only the operators you want.=C2=A0 (Something like `b=
oost::operators` can make this a easier to achieve.)=C2=A0 <br><br></div><d=
iv>John <br></div><span class=3D""><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
See my blog post about it for rationale:<br>
<a href=3D"http://foonathan.net/blog/2016/10/19/strong-typedefs.html" rel=
=3D"noreferrer" target=3D"_blank">http://foonathan.net/blog/<wbr>2016/10/19=
/strong-typedefs.<wbr>html</a><br>
<br>
--<br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%=
40gmail.com" rel=3D"noreferrer" target=3D"_blank">https://groups.google.com=
/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/95d6f9b7-2f4c-4b1e-<wbr>6e29-=
477a9cb3a66d%40gmail.com</a>.<br>
</blockquote></span></div></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-oLZBStoAmSjODiCAeq9M=
zDooq%2BTkzsV9sA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/st=
d-<wbr>proposals/CABPJVnR1kzLAp3c-<wbr>oLZBStoAmSjODiCAeq9MzDooq%<wbr>2BTkz=
sV9sA%40mail.gmail.com</a>.<br>
</blockquote></div><br><br clear=3D"all"><div><br></div>-- <br><div class=
=3D"gmail_signature" data-smartmail=3D"gmail_signature"><div dir=3D"ltr"><d=
iv>Be seeing you,<br></div>Tony<br></div></div>
</div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOHCbit4n0oyoGp0ymu70APJg_UuNYyxd%2B=
t1FQoU96DMmh8JKw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOHCbit4n0oyoG=
p0ymu70APJg_UuNYyxd%2Bt1FQoU96DMmh8JKw%40mail.gmail.com</a>.<br />
--f403045ceeec36fdca0554c4c28d--
.
Author: Zach Laine <whatwasthataddress@gmail.com>
Date: Thu, 20 Jul 2017 15:13:44 -0500
Raw View
--f403045f6d5cb8e3f30554c5626f
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Another common use case is x,y coordinates passed as arguments in GUI code:
move_window(y, x); // oops!
If x and y are typed, I get to detect such errors at compile time. Cool --
ship it!
The only problem with this is that I also want to use x and y in a bit of
math to determine where the window goes, so I need all the arithmetic *and*
comparison operators. Choosing which strong-typedefs get which operations
is the real challenge any such feature needs to overcome.
In one GUI system I used to maintain, I made such strong typedefs for int
window positions, but much of my math also included floating point
operations on intermediate values. You can imagine what a sticky wicket
this became.
Zach
On Thu, Jul 20, 2017 at 2:28 PM, Tony V E <tvaneerd@gmail.com> wrote:
> Here's some example code which may or may not be helped by some form of
> "strong typedef".
>
> https://github.com/tvaneerd/code/blob/master/StrongId.h
>
> It wraps a string or int or whatever, and makes it a unique type (based o=
n
> a Tag template param).
> Since it is for IDs, it doesn't want arithmetic (or concatenation)
> operations, but it does want equality and less (et al).
>
> I suspect you always want to "inherit" =3D=3D and !=3D, and most likely
> relational ordering.
>
>
> On Thu, Jul 20, 2017 at 6:59 AM, John McFarlane <john@mcfarlane.name>
> wrote:
>
>> On Thu, Jul 20, 2017 at 2:29 AM Jonathan M=C3=BCller <
>> jonathanmueller.dev@gmail.com> wrote:
>>
>>> On 20.07.2017 11:25, Alex Newlifer wrote:
>>> > Hello!
>>> >
>>> > I suggest to use `explicit` specifier for using-declaration to make
>>> strong
>>> > typedef (aka completely new type).
>>> >
>>> > Simple example:
>>> > ```
>>> > using explicit my_int_t =3D int;
>>> >
>>> > /* Now we cannot pass into function foo int values without explicit
>>> cast.
>>> > */
>>> > void foo(my_int_t val)
>>> > {}
>>> >
>>> > int val =3D 0;
>>> >
>>> > foo(val); // Error
>>> > foo(static_cast<my_int_t>(val)); // Ok
>>> > foo(my_int_t(0)); // Ok
>>> > ```
>>> >
>>>
>>> While this would be a great step forward, this is not useful for all
>>> cases.
>>>
>>
>> Yes, something like this could be helpful for improving type safety.
>>
>> In a strong typedef you'd want to keep certain functions like an
>>> `operator+` in your example, but not necessarily *all* operators, membe=
r
>>> functions.
>>>
>>
>> Perhaps removing the operators of a type should be separated from the
>> concern of removing implicit casting. If you don't want the full
>> complement of arithmetic, maybe you should not start with `int` at all, =
but
>> instead 'explicitly alias' a type with only the operators you want.
>> (Something like `boost::operators` can make this a easier to achieve.)
>>
>> John
>>
>>>
>>> See my blog post about it for rationale:
>>> http://foonathan.net/blog/2016/10/19/strong-typedefs.html
>>>
>>> --
>>> 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-proposals+unsubscribe@isocpp.org.
>>> To post to this group, send email to std-proposals@isocpp.org.
>>> To view this discussion on the web visit https://groups.google.com/a/is
>>> ocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-
>>> 477a9cb3a66d%40gmail.com.
>>>
>> --
>> You received this message because you are subscribed to the Google Group=
s
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n
>> email to std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-oLZBStoAmSjO
>> DiCAeq9MzDooq%2BTkzsV9sA%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1k=
zLAp3c-oLZBStoAmSjODiCAeq9MzDooq%2BTkzsV9sA%40mail.gmail.com?utm_medium=3De=
mail&utm_source=3Dfooter>
>> .
>>
>
>
>
> --
> Be seeing you,
> Tony
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAOHCbit4n0oyoGp0ymu70APJg_
> UuNYyxd%2Bt1FQoU96DMmh8JKw%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOHCbit4n0=
oyoGp0ymu70APJg_UuNYyxd%2Bt1FQoU96DMmh8JKw%40mail.gmail.com?utm_medium=3Dem=
ail&utm_source=3Dfooter>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CALOpkJArd8YyDm0gJuVhfgbRv2TrWDczTvjGHMnyoX6pu68=
6wQ%40mail.gmail.com.
--f403045f6d5cb8e3f30554c5626f
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Another common use case is x,y coordinates passed as argum=
ents in GUI code:<div><br></div><div>move_window(y, x); // oops!</div><div>=
<br></div><div>If x and y are typed, I get to detect such errors at compile=
time.=C2=A0 Cool -- ship it!</div><div><br></div><div>The only problem wit=
h this is that I also want to use x and y in a bit of math to determine whe=
re the window goes, so I need all the arithmetic *and* comparison operators=
..=C2=A0 Choosing which strong-typedefs get which operations is the real cha=
llenge any such feature needs to overcome.</div><div><br></div><div>In one =
GUI system I used to maintain, I made such strong typedefs for int window p=
ositions, but much of my math also included floating point operations on in=
termediate values.=C2=A0 You can imagine what a sticky wicket this became.<=
/div><div><br></div><div>Zach<br><div class=3D"gmail_extra"><br><div class=
=3D"gmail_quote">On Thu, Jul 20, 2017 at 2:28 PM, Tony V E <span dir=3D"ltr=
"><<a href=3D"mailto:tvaneerd@gmail.com" target=3D"_blank">tvaneerd@gmai=
l.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"m=
argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"l=
tr">Here's some example code which may or may not be helped by some for=
m of "strong typedef".<div><br></div><div><a href=3D"https://gith=
ub.com/tvaneerd/code/blob/master/StrongId.h" target=3D"_blank">https://gith=
ub.com/tvaneerd/<wbr>code/blob/master/StrongId.h</a><br></div><div><br></di=
v><div>It wraps a string or int or whatever, and makes it a unique type (ba=
sed on a Tag template param).</div><div>Since it is for IDs, it doesn't=
want arithmetic (or concatenation) operations, but it does want equality a=
nd less (et al).</div><div><br></div><div>I suspect you always want to &quo=
t;inherit" =3D=3D and !=3D, and most likely relational ordering.</div>=
<div><br></div></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quo=
te">On Thu, Jul 20, 2017 at 6:59 AM, John McFarlane <span dir=3D"ltr"><<=
a href=3D"mailto:john@mcfarlane.name" target=3D"_blank">john@mcfarlane.name=
</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin=
:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><=
div class=3D"gmail_quote"><span><div dir=3D"ltr">On Thu, Jul 20, 2017 at 2:=
29 AM Jonathan M=C3=BCller <<a href=3D"mailto:jonathanmueller.dev@gmail.=
com" target=3D"_blank">jonathanmueller.dev@gmail.com</a><wbr>> wrote:<br=
></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-=
left:1px #ccc solid;padding-left:1ex">On 20.07.2017 11:25, Alex Newlifer wr=
ote:<br>
> Hello!<br>
><br>
> I suggest to use `explicit` specifier for using-declaration to make st=
rong<br>
> typedef (aka completely new type).<br>
><br>
> Simple example:<br>
> ```<br>
> using explicit my_int_t =3D int;<br>
><br>
> /* Now we cannot pass into function foo int values without explicit ca=
st.<br>
> */<br>
> void foo(my_int_t val)<br>
> {}<br>
><br>
> int val =3D 0;<br>
><br>
> foo(val); // Error<br>
> foo(static_cast<my_int_t>(val)<wbr>); // Ok<br>
> foo(my_int_t(0)); // Ok<br>
> ```<br>
><br>
<br>
While this would be a great step forward, this is not useful for all cases.=
<br></blockquote><div><br></div></span><div>Yes, something like this could =
be helpful for improving type safety.<br><br></div><span><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex">
In a strong typedef you'd want to keep certain functions like an<br>
`operator+` in your example, but not necessarily *all* operators, member<br=
>
functions.<br></blockquote><div><br></div></span><div>Perhaps removing the =
operators of a type should be separated from the concern of removing implic=
it casting.=C2=A0 If you don't want the full complement of arithmetic, =
maybe you should not start with `int` at all, but instead 'explicitly a=
lias' a type with only the operators you want.=C2=A0 (Something like `b=
oost::operators` can make this a easier to achieve.)=C2=A0 <br><br></div><d=
iv>John <br></div><span><blockquote class=3D"gmail_quote" style=3D"margin:0=
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
See my blog post about it for rationale:<br>
<a href=3D"http://foonathan.net/blog/2016/10/19/strong-typedefs.html" rel=
=3D"noreferrer" target=3D"_blank">http://foonathan.net/blog/2016<wbr>/10/19=
/strong-typedefs.html</a><br>
<br>
--<br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/95d6f9b7-2f4c-4b1e-6e29-477a9cb3a66d%=
40gmail.com" rel=3D"noreferrer" target=3D"_blank">https://groups.google.com=
/a/is<wbr>ocpp.org/d/msgid/std-proposals<wbr>/95d6f9b7-2f4c-4b1e-6e29-<wbr>=
477a9cb3a66d%40gmail.com</a>.<br>
</blockquote></span></div></div><span>
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isoc<wbr>pp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CABPJVnR1kzLAp3c-oLZBStoAmSjODiCAeq9M=
zDooq%2BTkzsV9sA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/st=
d-proposals<wbr>/CABPJVnR1kzLAp3c-oLZBStoAmSjO<wbr>DiCAeq9MzDooq%2BTkzsV9sA=
%<wbr>40mail.gmail.com</a>.<span class=3D"HOEnZb"><font color=3D"#888888"><=
br>
</font></span></blockquote></div><span class=3D"HOEnZb"><font color=3D"#888=
888"><br><br clear=3D"all"><div><br></div>-- <br><div class=3D"m_4845060074=
273617999gmail_signature" data-smartmail=3D"gmail_signature"><div dir=3D"lt=
r"><div>Be seeing you,<br></div>Tony<br></div></div>
</font></span></div><span class=3D"HOEnZb"><font color=3D"#888888">
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAOHCbit4n0oyoGp0ymu70APJg_UuNYyxd%2B=
t1FQoU96DMmh8JKw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/st=
d-<wbr>proposals/<wbr>CAOHCbit4n0oyoGp0ymu70APJg_<wbr>UuNYyxd%2Bt1FQoU96DMm=
h8JKw%<wbr>40mail.gmail.com</a>.<br>
</font></span></blockquote></div><br></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CALOpkJArd8YyDm0gJuVhfgbRv2TrWDczTvjG=
HMnyoX6pu686wQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALOpkJArd8YyDm0g=
JuVhfgbRv2TrWDczTvjGHMnyoX6pu686wQ%40mail.gmail.com</a>.<br />
--f403045f6d5cb8e3f30554c5626f--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 20 Jul 2017 17:10:44 -0700 (PDT)
Raw View
------=_Part_1051_1626593663.1500595844936
Content-Type: multipart/alternative;
boundary="----=_Part_1052_1461802378.1500595844936"
------=_Part_1052_1461802378.1500595844936
Content-Type: text/plain; charset="UTF-8"
On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:
>
> Another common use case is x,y coordinates passed as arguments in GUI code:
>
Couldn't you just do that with typed integers? That is, a template that
uses a typename as the "type", which only allows math between values with
the same typename, and no implicit conversions between values with
different typenames? I don't see why you would need an alias at all.
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c80ad8de-18d8-430c-b7e3-60745f7bd215%40isocpp.org.
------=_Part_1052_1461802378.1500595844936
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine=
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Anothe=
r common use case is x,y coordinates passed as arguments in GUI code:</div>=
</blockquote><div><br>Couldn't you just do that with typed integers? Th=
at is, a template that uses a typename as the "type", which only =
allows math between values with the same typename, and no implicit conversi=
ons between values with different typenames? I don't see why you would =
need an alias at all.<br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c80ad8de-18d8-430c-b7e3-60745f7bd215%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c80ad8de-18d8-430c-b7e3-60745f7bd215=
%40isocpp.org</a>.<br />
------=_Part_1052_1461802378.1500595844936--
------=_Part_1051_1626593663.1500595844936--
.
Author: Zach Laine <whatwasthataddress@gmail.com>
Date: Thu, 20 Jul 2017 19:41:27 -0500
Raw View
--94eb2c1256a027284e0554c92044
Content-Type: text/plain; charset="UTF-8"
On Thu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
> On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:
>>
>> Another common use case is x,y coordinates passed as arguments in GUI
>> code:
>>
>
> Couldn't you just do that with typed integers? That is, a template that
> uses a typename as the "type", which only allows math between values with
> the same typename, and no implicit conversions between values with
> different typenames? I don't see why you would need an alias at all.
>
Right, and that's what I did. My understanding of the language feature
proposed is that I would have very simple syntax for specifying such types,
rather than having to write them from scratch.
The point of my post is to point out that that's not easy.
Zach
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com.
--94eb2c1256a027284e0554c92044
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On T=
hu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <span dir=3D"ltr"><<a href=3D"m=
ailto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>></s=
pan> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><span class=
=3D"">On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:<blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Another common use cas=
e is x,y coordinates passed as arguments in GUI code:</div></blockquote></s=
pan><div><br>Couldn't you just do that with typed integers? That is, a =
template that uses a typename as the "type", which only allows ma=
th between values with the same typename, and no implicit conversions betwe=
en values with different typenames? I don't see why you would need an a=
lias at all.<br></div></div></blockquote><div><br></div><div>Right, and tha=
t's what I did.=C2=A0 My understanding of the language feature proposed=
is that I would have very simple syntax for specifying such types, rather =
than having to write them from scratch.</div><div><br></div><div>The point =
of my post is to point out that that's not easy.</div><div><br></div><d=
iv>Zach</div></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7=
W3-gc28fs3QRvQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREn=
bQs9YSiWiPTFpYKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com</a>.<br />
--94eb2c1256a027284e0554c92044--
.
Author: Eugenio Bargiacchi <svalorzen@gmail.com>
Date: Fri, 21 Jul 2017 10:08:19 +0200
Raw View
--f40304379a8c3fde9b0554cf5ead
Content-Type: text/plain; charset="UTF-8"
The syntax I have proposed at the beginning of the overall thread would
allow you to specify with arbitrary precision the types you need, and once
that is done require little to no additional code to create multiple type
copies of the one you have specified.
I am currently working on a Clang patch to showcase a subset of the
features I have proposed. It's not missing much, but unfortunately I've had
little time to work on it in the past few months. Once that's done I'll
post here, along with an example small library to show how my proposal
could be used and to receive more feedback.
Eugenio
On Fri, Jul 21, 2017 at 2:41 AM, Zach Laine <whatwasthataddress@gmail.com>
wrote:
> On Thu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
>
>> On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:
>>>
>>> Another common use case is x,y coordinates passed as arguments in GUI
>>> code:
>>>
>>
>> Couldn't you just do that with typed integers? That is, a template that
>> uses a typename as the "type", which only allows math between values with
>> the same typename, and no implicit conversions between values with
>> different typenames? I don't see why you would need an alias at all.
>>
>
> Right, and that's what I did. My understanding of the language feature
> proposed is that I would have very simple syntax for specifying such types,
> rather than having to write them from scratch.
>
> The point of my post is to point out that that's not easy.
>
> Zach
>
> --
> 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/gkJUVnL-Fmg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFp
> YKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvqHeVqPYykUjYWH%2B-kF0PO_Y7e5sHsLFBVmH_kWefz_g%40mail.gmail.com.
--f40304379a8c3fde9b0554cf5ead
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div>The syntax I have proposed at the beginning of t=
he overall thread would allow you to specify with arbitrary precision the t=
ypes you need, and once that is done require little to no additional code t=
o create multiple type copies of the one you have specified.<br><br></div>I=
am currently working on a Clang patch to showcase a subset of the features=
I have proposed. It's not missing much, but unfortunately I've had=
little time to work on it in the past few months. Once that's done I&#=
39;ll post here, along with an example small library to show how my proposa=
l could be used and to receive more feedback.<br><br></div>Eugenio<br><div>=
<div><div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Fri,=
Jul 21, 2017 at 2:41 AM, Zach Laine <span dir=3D"ltr"><<a href=3D"mailt=
o:whatwasthataddress@gmail.com" target=3D"_blank">whatwasthataddress@gmail.=
com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr=
"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"">On=
Thu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <span dir=3D"ltr"><<a href=3D=
"mailto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>><=
/span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><span>On T=
hursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:<blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div dir=3D"ltr">Another common use case is x,y c=
oordinates passed as arguments in GUI code:</div></blockquote></span><div><=
br>Couldn't you just do that with typed integers? That is, a template t=
hat uses a typename as the "type", which only allows math between=
values with the same typename, and no implicit conversions between values =
with different typenames? I don't see why you would need an alias at al=
l.<br></div></div></blockquote><div><br></div></span><div>Right, and that&#=
39;s what I did.=C2=A0 My understanding of the language feature proposed is=
that I would have very simple syntax for specifying such types, rather tha=
n having to write them from scratch.</div><div><br></div><div>The point of =
my post is to point out that that's not easy.</div><div><br></div><div>=
Zach</div></div></div></div><span class=3D"">
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/g=
kJUVnL-Fmg/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7=
W3-gc28fs3QRvQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-=
<wbr>proposals/<wbr>CALOpkJCC4VALGREnbQs9YSiWiPTFp<wbr>YKHB4H7W3-gc28fs3QRv=
Q%40mail.<wbr>gmail.com</a>.<br>
</blockquote></div><br></div></div></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvqHeVqPYykUjYWH%2B-kF0PO_Y=
7e5sHsLFBVmH_kWefz_g%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2B=
vqHeVqPYykUjYWH%2B-kF0PO_Y7e5sHsLFBVmH_kWefz_g%40mail.gmail.com</a>.<br />
--f40304379a8c3fde9b0554cf5ead--
.
Author: Dejan Milosavljevic <dmilos@gmail.com>
Date: Sat, 22 Jul 2017 14:35:12 +0200
Raw View
--001a114b2fe493cc760554e73601
Content-Type: text/plain; charset="UTF-8"
In Konstantin Drozdov's list I'd like to add two more items( questions ).
We have (1)*'inheritance'* problem with strog typdefs'. What to do with
unwanted property of base type.
*Inherit all then delete* or *inherit nothing then extend*. What is
inheritance in this problem?
Here is example of *inherit all then delete*.
Fine tuning( removing operators or functions ) of strong typedefs might
look like this:
// Definition:
using explicit my_string_t = std::string; //!< "Inherit" all and everything.
// delete. Applies ONLY to strong typedef.
std::string operator+( my_string_t const& left, my_string_t const& right
)delete;
ostream& operator<< (ostream& os, my_string_t const& str)delete ;
This rise question: (2)H*ow far with tuning we may go?*
Hera is example:
my_string_t my_s;
sort::sort( my_s.begin(), my_s.end() ); //!< Is this deletable??
void sort::sort( my_string_t::iterator, my_string_t::iterator )delete;
template <class Compare>
void sort::sort( my_string_t::iterator, my_string_t::iterator, Compare
comp )delete;
Now we have weak( anything related with base type ) and strong( only
direct usage of base type ) tuning.
On Fri, Jul 21, 2017 at 10:08 AM, Eugenio Bargiacchi <svalorzen@gmail.com>
wrote:
> The syntax I have proposed at the beginning of the overall thread would
> allow you to specify with arbitrary precision the types you need, and once
> that is done require little to no additional code to create multiple type
> copies of the one you have specified.
>
> I am currently working on a Clang patch to showcase a subset of the
> features I have proposed. It's not missing much, but unfortunately I've had
> little time to work on it in the past few months. Once that's done I'll
> post here, along with an example small library to show how my proposal
> could be used and to receive more feedback.
>
> Eugenio
>
> On Fri, Jul 21, 2017 at 2:41 AM, Zach Laine <whatwasthataddress@gmail.com>
> wrote:
>
>> On Thu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
>>
>>> On Thursday, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:
>>>>
>>>> Another common use case is x,y coordinates passed as arguments in GUI
>>>> code:
>>>>
>>>
>>> Couldn't you just do that with typed integers? That is, a template that
>>> uses a typename as the "type", which only allows math between values with
>>> the same typename, and no implicit conversions between values with
>>> different typenames? I don't see why you would need an alias at all.
>>>
>>
>> Right, and that's what I did. My understanding of the language feature
>> proposed is that I would have very simple syntax for specifying such types,
>> rather than having to write them from scratch.
>>
>> The point of my post is to point out that that's not easy.
>>
>> Zach
>>
>> --
>> 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/is
>> ocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> To view this discussion on the web visit https://groups.google.com/a/is
>> ocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTF
>> pYKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com
>> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7W3-gc28fs3QRvQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>
> --
> 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-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvqHeVqPYykUjYWH%2B-kF0PO_
> Y7e5sHsLFBVmH_kWefz_g%40mail.gmail.com
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvqHeVqPYykUjYWH%2B-kF0PO_Y7e5sHsLFBVmH_kWefz_g%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAEfefmxO3m0%3DW5f%3Dwe%3DdxJ7pm8N4tyMwB2GngG6h8pD-WYo0qg%40mail.gmail.com.
--001a114b2fe493cc760554e73601
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>In Konstantin Drozdov's list I'd like to add =
two more items( questions ).</div><div><br></div><div>We have (1)<u>'in=
heritance'</u> problem with strog typdefs'.=C2=A0What to do with un=
wanted=C2=A0property of base type.</div><div><em>Inherit all=C2=A0then <fon=
t face=3D"monospace,monospace">delete</font></em> or <em>inherit nothing th=
en extend</em>.=C2=A0 What is inheritance in this problem?</div><div><br></=
div><div><br></div><div>Here is example of <em>inherit all=C2=A0then delete=
</em>.</div><div><br></div><div>Fine tuning( removing operators or function=
s ) of strong typedefs might look like this:</div><div><div>=C2=A0</div></d=
iv><div>// Definition:<div>=C2=A0</div></div><blockquote style=3D"margin-ri=
ght:0px" dir=3D"ltr"><div><font face=3D"monospace,monospace">using explicit=
my_string_t =3D std::string; //!< "Inherit" all and everythin=
g.</font></div></blockquote><div>=C2=A0</div><div>// <font face=3D"monospac=
e,monospace">delete</font>. Applies=C2=A0ONLY to strong typedef.<div>=C2=A0=
</div></div><blockquote style=3D"margin-right:0px"><div><font face=3D"monos=
pace,monospace">std::string operator+( my_string_t const& left, my_stri=
ng_t const& right )delete;</font></div><div><font face=3D"monospace,mon=
ospace">ostream& operator<< (ostream& os, my_string_t const&a=
mp; str)delete ;</font></div></blockquote><div>=C2=A0</div><div><div>=C2=A0=
</div></div><div>This rise question: (2)H<u>ow far with tuning we may go?</=
u></div><div>Hera is example:</div><blockquote style=3D"margin-right:0px"><=
div><font face=3D"monospace,monospace">my_string_t my_s;</font></div><div><=
font face=3D"monospace,monospace">sort::sort( my_s.begin(), my_s.end() ); /=
/!< Is this deletable??</font></div><div><font face=3D"Courier New"><br>=
</font></div><div><font face=3D"Courier New">void sort::sort( my_string_t::=
iterator, my_string_t::iterator )delete;</font></div><div><font face=3D"Cou=
rier New">template <class Compare></font></div><div><font face=3D"Cou=
rier New"><div><font face=3D"Courier New">=C2=A0=C2=A0=C2=A0 void sort::sor=
t( my_string_t::iterator, my_string_t::iterator, Compare comp=C2=A0)delete;=
</font></div></font><div><br></div></div></blockquote><div><div>=C2=A0Now w=
e have weak( anything related with=C2=A0base type ) and strong( only direct=
usage of base type ) tuning.</div></div></div><div class=3D"gmail_extra"><=
br><div class=3D"gmail_quote">On Fri, Jul 21, 2017 at 10:08 AM, Eugenio Bar=
giacchi <span dir=3D"ltr"><<a href=3D"mailto:svalorzen@gmail.com" target=
=3D"_blank">svalorzen@gmail.com</a>></span> wrote:<br><blockquote class=
=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr"><div><div>The syntax I have proposed at the =
beginning of the overall thread would allow you to specify with arbitrary p=
recision the types you need, and once that is done require little to no add=
itional code to create multiple type copies of the one you have specified.<=
br><br></div>I am currently working on a Clang patch to showcase a subset o=
f the features I have proposed. It's not missing much, but unfortunatel=
y I've had little time to work on it in the past few months. Once that&=
#39;s done I'll post here, along with an example small library to show =
how my proposal could be used and to receive more feedback.<br><br></div>Eu=
genio<br><div><div><div><div class=3D"gmail_extra"><br><div class=3D"gmail_=
quote"><span>On Fri, Jul 21, 2017 at 2:41 AM, Zach Laine <span dir=3D"ltr">=
<<a href=3D"mailto:whatwasthataddress@gmail.com" target=3D"_blank">whatw=
asthataddress@gmail.com</a>></span> wrote:<br></span><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-=
left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">=
<span><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote=
"><span>On Thu, Jul 20, 2017 at 7:10 PM, Nicol Bolas <span dir=3D"ltr"><=
<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.co=
m</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margi=
n:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);bor=
der-left-width:1px;border-left-style:solid"><div dir=3D"ltr"><span>On Thurs=
day, July 20, 2017 at 4:13:47 PM UTC-4, Zach Laine wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-=
left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">=
<div dir=3D"ltr">Another common use case is x,y coordinates passed as argum=
ents in GUI code:</div></blockquote></span><div><br>Couldn't you just d=
o that with typed integers? That is, a template that uses a typename as the=
"type", which only allows math between values with the same type=
name, and no implicit conversions between values with different typenames? =
I don't see why you would need an alias at all.<br></div></div></blockq=
uote><div><br></div></span><div>Right, and that's what I did.=C2=A0 My =
understanding of the language feature proposed is that I would have very si=
mple syntax for specifying such types, rather than having to write them fro=
m scratch.</div><div><br></div><div>The point of my post is to point out th=
at that's not easy.</div><div><br></div><div>Zach</div></div></div></di=
v></span><span>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/gkJUVnL-Fmg/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/is<wbr>ocpp.org/d/topic/std-proposals<wbr>/g=
kJUVnL-Fmg/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isoc<wbr>pp.org</a>.<span><br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span></span><spa=
n>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CALOpkJCC4VALGREnbQs9YSiWiPTFpYKHB4H7=
W3-gc28fs3QRvQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
target=3D"_blank">https://groups.google.com/a/is<wbr>ocpp.org/d/msgid/std-=
proposals<wbr>/CALOpkJCC4VALGREnbQs9YSiWiPTF<wbr>pYKHB4H7W3-gc28fs3QRvQ%40m=
ail.<wbr>gmail.com</a>.<br>
</span></blockquote></div><br></div></div></div></div></div><span>
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAHfn%3D%2BvqHeVqPYykUjYWH%2B-kF0PO_Y=
7e5sHsLFBVmH_kWefz_g%40mail.gmail.com?utm_medium=3Demail&utm_source=3Df=
ooter" target=3D"_blank">https://groups.google.com/a/<wbr>isocpp.org/d/msgi=
d/std-<wbr>proposals/CAHfn%3D%<wbr>2BvqHeVqPYykUjYWH%2B-kF0PO_<wbr>Y7e5sHsL=
FBVmH_kWefz_g%40mail.<wbr>gmail.com</a>.<br>
</blockquote></div><br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAEfefmxO3m0%3DW5f%3Dwe%3DdxJ7pm8N4ty=
MwB2GngG6h8pD-WYo0qg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAEfefmxO3m=
0%3DW5f%3Dwe%3DdxJ7pm8N4tyMwB2GngG6h8pD-WYo0qg%40mail.gmail.com</a>.<br />
--001a114b2fe493cc760554e73601--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 22 Jul 2017 07:41:23 -0700 (PDT)
Raw View
------=_Part_2074_2050319834.1500734483738
Content-Type: multipart/alternative;
boundary="----=_Part_2075_2128618145.1500734483738"
------=_Part_2075_2128618145.1500734483738
Content-Type: text/plain; charset="UTF-8"
On Thursday, July 20, 2017 at 8:37:02 AM UTC-4, drozdovk...@gmail.com wrote:
>
> Here is some ideas:
>
> 1. Strong typedefs are declared by 'using explicit alias_type = type'.
> 2. Strong typedefs can not be implicitly casted but can be explicitly
> casted.
> 3. Strong typedefs are different types by mean of template arguments.
> 4. Strong typedefs are guaranteed to be exactly the same in-memory and are
> exactly the same type by mean of RTTI (this requires some review over
> std::variant and other typeinfo-dependent templates).
>
So "strong" types are different for the purposes of template arguments. But
they're *not* different for the purposes of RTTI? So, that means that this
will be allowed:
using explicit alias = int;
any a(in_place_t<alias>, alias(5));
int i = any_cast<int>(a);
`any_cast`'s checking is based on `type_info` extracted via RTTI. But
`any`'s constructor is based on template instantiation; `in_place_t<alias>`
is a different type from `in_place_t<int>`. It is incredibly silly for the
following to be the case:
auto it1 = typeid(in_place_t<alias>);
auto it2 = typeid(in_place_t<int>);
auto i1 = typeid(alias);
auto i2 = typeid(int);
assert(it1 == it2); //fails
assert(i1 == i2); //succeeds
No, if the types are different, then the *types are different*. The whole
point of a strong typedef is that it is a different type. So it should be a
different type in *all ways* that are detectable. We can have a query to
detect the underlying type of the alias. But as far as the actual type is
concerned, it ought to be different in all things.
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/37f8e529-054a-4519-8e62-69dd53ebd932%40isocpp.org.
------=_Part_2075_2128618145.1500734483738
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Thursday, July 20, 2017 at 8:37:02 AM UTC-4, drozdovk..=
..@gmail.com wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"=
ltr">Here is some ideas:<br><br>1. Strong typedefs are declared by 'usi=
ng explicit alias_type =3D type'.<br>2. Strong typedefs can not be impl=
icitly casted but can be explicitly casted.<br>3. Strong typedefs are diffe=
rent types by mean of template arguments.<br>4. Strong typedefs are guarant=
eed to be exactly the same in-memory and are exactly the same type by mean =
of RTTI (this requires some review over std::variant and other typeinfo-dep=
endent templates).<br></div></blockquote><div><br>So "strong" typ=
es are different for the purposes of template arguments. But they're <i=
>not</i> different for the purposes of RTTI? So, that means that this will =
be allowed:<br><br><div style=3D"background-color: rgb(250, 250, 250); bord=
er-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; overf=
low-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprint"><d=
iv class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by=
-prettify">using</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">exp=
licit</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">alias</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>any a</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">in_place_t</span><span style=3D"color: #080;" class=3D"styled-by-prett=
ify"><alias></span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">alias</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span s=
tyle=3D"color: #066;" class=3D"styled-by-prettify">5</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">));</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> i </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> any_cast</span><span style=3D"color: #080;" class=3D"styled-by-p=
rettify"><int></span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span=
></div></code></div><br>`any_cast`'s checking is based on `type_info` e=
xtracted via RTTI. But `any`'s constructor is based on template instant=
iation; `in_place_t<alias>` is a different type from `in_place_t<i=
nt>`. It is incredibly silly for the following to be the case:<br><br><d=
iv style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 18=
7, 187); border-style: solid; border-width: 1px; overflow-wrap: break-word;=
" class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subpretty=
print"><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> it1 </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">typeid</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">in_place_t</span><span style=3D"color: #080;" clas=
s=3D"styled-by-prettify"><alias></span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled=
-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> it2 </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">typeid</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">in_place_t</span><span sty=
le=3D"color: #080;" class=3D"styled-by-prettify"><int></span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> i1 </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">typeid</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">alias=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> i2 </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">typeid</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">asser=
t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">it1 </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">=3D=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> it2</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">//fails</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">assert</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">i1 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> i2</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">//succeeds</span></div></code><=
/div><br>No, if the types are different, then the <i>types are different</i=
>. The whole point of a strong typedef is that it is a different type. So i=
t should be a different type in <i>all ways</i> that are detectable. We can=
have a query to detect the underlying type of the alias. But as far as the=
actual type is concerned, it ought to be different in all things.</div></d=
iv>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/37f8e529-054a-4519-8e62-69dd53ebd932%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/37f8e529-054a-4519-8e62-69dd53ebd932=
%40isocpp.org</a>.<br />
------=_Part_2075_2128618145.1500734483738--
------=_Part_2074_2050319834.1500734483738--
.