Topic: Uniform aliasing. or generalized 'using' statement,
Author: Viacheslav Usov <via.usov@gmail.com>
Date: Wed, 27 Jan 2016 15:56:04 +0100
Raw View
--047d7b6725dc4b080d052a52009c
Content-Type: text/plain; charset=UTF-8
Prior work:
[1] n1449
[2] n1489
Nothing in this proposal is really new. It was nearly fully anticipated in
[2], and, per [1], the strong preference at a straw poll at an Evolution
Working Group meeting in favour of the syntax 'using X = Y' *stemmed partly
from the desire to use a syntax that might be compatible with the
non-template aliasing direction briefly outlined above*, where *the
non-template aliasing direction *was a way to alias functions, which was
not standardised.
What's wrong with 'using', anyway?
Currently, the keyword 'using' is part of
1. A *using-declaration: *using typename_opt *nested-name-specifier
unqualified-id *[namespace.udecl];
2. A *using-directive*: *attribute-specifier-seq*_opt using namespace
*nested-name-specifier_opt
namespace-name *[namespace.udir];
3. An *alias-declaration:* using *identifier attribute-specifier-seq_opt =
type-id *[dcl.dcl];
4. An *alias template *[temp.alias].
Despite the seemingly similar syntax in all the cases, there are some
arcane limitations that are difficult to characterize except as arbitrary.
For example:
namespace A
{
struct c { static int k; };
int i;
void f() {}
void h(int) {};
void h(double) {};
namespace n {}
enum class e { v };
template<typename X, typename Y> struct s {};
template<typename X, typename Y> void g() {}
}
using A::c; // OK
using C = A::c; // OK
using A::c::k; // ill-formed, instead use the following
auto &k = A::c::k;
using K = A::c::k; // ill-formed, instead use the following
auto &K = A::c::k;
using A::i; // OK
using I = A::i; // ill-formed, instead use the following
auto &I = A::i;
using A::f; // OK
using F = A::f; // ill-formed, instead use the following
auto &F = A::f;
using A::h; // OK
using H = A::h; // ill-formed, and the following does not work
auto &H = A::h; // oops, but the following works
template<typename ...X> // simplicity itself
auto H(X &&...x) -> decltype(A::h(std::forward<X>(x)...))
{ return A::h(std::forward<X>(x)...); }
using Hi = A::h(int); // ill-formed, instead use the following
auto Hi(int x) -> decltype(A::h(x)) { return A::h(x); } // OK
using A::n; // ill-formed, instead use the following
using namespace A::n;
using N = A::n; // ill-formed, instead use the following
namespace N = A::n;
using A::e::v; // ill-formed, instead use the following
enum { v = A::e::v }; // but ::v is not fully equivalent to A::e::v
using V = A::e::v; // ill-formed, instead use the following
enum { V = A::e::v }; // but ::V is not fully equivalent to A::e::v
template<typename X> using A::s<X, int>; // ill-formed, instead use the
following
template<typename X> using s = A::s<X, int>;
template<typename X> using A::g<X, int>; // ill-formed, instead use the
following
template<typename X> auto g() -> decltype(A::g<X, int>()) { return A::g<X,
int>(); }
template<typename X> using G = A::g<X, int>; // ill-formed, instead use the
following
template<typename X> auto G() -> decltype(A::g<X, int>()) { return A::g<X,
int>(); }
In the example above, every mention of 'using' was an attempt to create an
alias for an existing entity, sometimes with a narrower meaning of the
alias. The example above demonstrates that current C++, while having a way
to define an alias for an entity in (just about) every practical case, does
not do so uniformly, thus lacking an important idiom. Sometimes correct C++
for an alias is trivial, sometimes highly involved.
A particular problem is that, without a uniform syntax for aliasing, some
generic code is impossible to write (or, at least, to write it easily). For
example, given entity E, there is no simple way to define alias F for E so
that F() is valid whenever E() is valid.
Proposal
I propose *uniform aliasing*, which is, essentially, making every mention
of 'using' in the example above (and similar cases that make sense) valid.
More generally, it is a simple way to say "X is another name for Y", no
matter what Y is.
In more concrete terms, the proposed syntax is a fusion of all the four
above-mentioned cases. I am not specifying the details of the syntax, but
the idea is that 'using Y' and 'using X = Y' should be possible whenever Y
denotes something that can be *meaningfully aliased*. *Meaningfully
aliased *is not yet defined; to initiate a discussion, I would say that at
least the following should be possible as Y: a namespace, a type, a
function (with optional overload selection as in [2]), an lvalue, or an
enumerator.
When it is desirable to disambiguate explicitly what kind of entity Y is,
one of 'auto', 'namespace' and 'typename' can be specified after 'using';
'using auto' signifies that Y is neither a namespace nor a type.
Please comment.
Cheers,
V.
--
---
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.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-proposals/.
--047d7b6725dc4b080d052a52009c
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Prior work:<div><br></div><div>[1] n1449</div><div><br></d=
iv><div>[2] n1489<br></div><div><br></div><div>Nothing in this proposal is =
really new. It was nearly fully anticipated in [2], and, per [1], the stron=
g preference at a straw poll at an Evolution Working Group meeting in favou=
r of the syntax 'using X =3D Y'=C2=A0<i style=3D"font-size:12.8px">=
stemmed partly from the desire to use a syntax that might be compatible wit=
h the non-template aliasing direction briefly outlined above</i>, where=C2=
=A0<i style=3D"font-size:12.8px">the non-template aliasing direction=C2=A0<=
/i>was a way to alias functions, which was not standardised.</div><div><br>=
</div><div>What's wrong with 'using', anyway?</div><div><br></d=
iv><div>Currently, the keyword 'using' is part of</div><div><br></d=
iv><div>1. A <i>using-declaration:=C2=A0</i>using typename_opt <i>nested-na=
me-specifier unqualified-id=C2=A0</i>[namespace.udecl];</div><div><br></div=
><div>2. A <i>using-directive</i>:=C2=A0<i>attribute-specifier-seq</i>_opt =
using namespace <i>nested-name-specifier_opt namespace-name=C2=A0</i>[names=
pace.udir];</div><div><br></div><div>3. An <i>alias-declaration:</i> using =
<i>identifier attribute-specifier-seq_opt =3D type-id=C2=A0</i>[dcl.dcl];</=
div><div><br></div><div>4. An <i>alias template=C2=A0</i>[temp.alias].</div=
><div><br></div><div>Despite the seemingly similar syntax in all the cases,=
there are some arcane limitations that are difficult to characterize excep=
t as arbitrary. For example:</div><div><br></div><div><div><div>namespace A=
</div><div>{</div><div>=C2=A0 =C2=A0 struct c { static int k; };</div><div>=
=C2=A0 =C2=A0 int i;</div><div>=C2=A0 =C2=A0 void f() {}</div><div>=C2=A0 =
=C2=A0 void h(int) {};</div><div>=C2=A0 =C2=A0 void h(double) {};</div><div=
>=C2=A0 =C2=A0 namespace n {}</div><div>=C2=A0 =C2=A0 enum class e { v };</=
div><div>=C2=A0 =C2=A0 template<typename X, typename Y> struct s {};<=
/div><div>=C2=A0 =C2=A0 template<typename X, typename Y> void g() {}<=
/div><div>}</div><div><br></div><div>using A::c; // OK</div><div>using C =
=3D A::c; // OK</div><div>using A::c::k; // ill-formed, instead use the fol=
lowing</div><div>auto &k =3D A::c::k;</div><div>using K =3D A::c::k; //=
ill-formed, instead use the following</div><div>auto &K =3D A::c::k;</=
div><div>using A::i; // OK</div><div>using I =3D A::i; // ill-formed, inste=
ad use the following</div><div>auto &I =3D A::i;</div><div>using A::f; =
// OK</div><div>using F =3D A::f; // ill-formed, instead use the following<=
/div><div>auto &F =3D A::f;</div><div>using A::h; // OK</div><div>using=
H =3D A::h; // ill-formed, and the following does not work</div><div>auto =
&H =3D A::h; // oops, but the following works</div><div>template<typ=
ename ...X> // simplicity itself</div><div>auto H(X &&...x) ->=
; decltype(A::h(std::forward<X>(x)...))</div><div>{ return A::h(std::=
forward<X>(x)...); }</div><div>using Hi =3D A::h(int); // ill-formed,=
instead use the following</div><div>auto Hi(int x) -> decltype(A::h(x))=
{ return A::h(x); } // OK</div><div>using A::n; // ill-formed, instead use=
the following</div><div>using namespace A::n;</div><div>using N =3D A::n; =
// ill-formed, instead use the following</div><div>namespace N =3D A::n;</d=
iv><div>using A::e::v; // ill-formed, instead use the following</div><div>e=
num { v =3D A::e::v }; // but ::v is not fully equivalent to A::e::v</div><=
div>using V =3D A::e::v; // ill-formed, instead use the following</div><div=
>enum { V =3D A::e::v }; // but ::V is not fully equivalent to A::e::v</div=
><div>template<typename X> using A::s<X, int>; // ill-formed, i=
nstead use the following</div><div>template<typename X> using s =3D A=
::s<X, int>;</div><div>template<typename X> using A::g<X, in=
t>; // ill-formed, instead use the following</div><div>template<typen=
ame X> auto g() -> decltype(A::g<X, int>()) { return A::g<X,=
int>(); }</div><div>template<typename X> using G =3D A::g<X, i=
nt>; // ill-formed, instead use the following</div><div>template<type=
name X> auto G() -> decltype(A::g<X, int>()) { return A::g<X=
, int>(); }</div></div></div><div><br></div><div>In the example above, e=
very mention of 'using' was an attempt to create an alias for an ex=
isting entity, sometimes with a narrower meaning of the alias. The example =
above demonstrates that current C++, while having a way to define an alias =
for an entity in (just about) every practical case, does not do so uniforml=
y, thus lacking an important idiom. Sometimes correct C++ for an alias is t=
rivial, sometimes highly involved.<br></div><div><br></div><div>A particula=
r problem is that, without a uniform syntax for aliasing, some generic code=
is impossible to write (or, at least, to write it easily). For example, gi=
ven entity E, there is no simple way to define alias F for E so that F() is=
valid whenever E() is valid.</div><div><br></div><div>Proposal<br></div><d=
iv><br></div><div>I propose <i>uniform aliasing</i>, which is, essentially,=
making every mention of 'using' in the example above (and similar =
cases that make sense) valid. More generally, it is a simple way to say &qu=
ot;X is another name for Y", no matter what Y is.</div><div><br></div>=
<div>In more concrete terms, the proposed syntax is a fusion of all the fou=
r above-mentioned cases. I am not specifying the details of the syntax, but=
the idea is that 'using Y' and 'using X =3D Y' should be p=
ossible whenever Y denotes something that can be <i>meaningfully aliased</i=
>. <i>Meaningfully aliased=C2=A0</i>is not yet defined; to initiate a discu=
ssion, I would say that at least the following should be possible as Y: a n=
amespace, a type, a function (with optional overload selection as in [2]), =
an lvalue, or an enumerator.</div><div><br></div><div>When it is desirable =
to disambiguate explicitly what kind of entity Y is, one of 'auto',=
'namespace' and 'typename' can be specified after 'usi=
ng'; 'using auto' signifies that Y is neither a namespace nor a=
type.<br></div><div><br></div><div>Please comment.</div><div><br></div><di=
v>Cheers,</div><div>V.</div><div><br></div></div>
<p></p>
-- <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+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 />
Visit this group at <a href=3D"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--047d7b6725dc4b080d052a52009c--
.