Topic: Type pack aliases
Author: Dmitry Baskakov <furax@yandex.ru>
Date: Mon, 9 May 2016 09:36:33 -0700 (PDT)
Raw View
------=_Part_3580_39015991.1462811793821
Content-Type: multipart/alternative;
boundary="----=_Part_3581_281892888.1462811793823"
------=_Part_3581_281892888.1462811793823
Content-Type: text/plain; charset=UTF-8
Definition
There is a proposal to extend C++ language core so that the developer would
be able to introduce aliases for the packs of types rather than for single
type. The meaning for `the pack of types` is same as when defining variadic
templates. The proposed syntax is as follows:
template <class ...Pack>
struct Packed
{
using ...packed_type = Pack...;
};
An alternative syntax should allow it to explicitly specify the list of
types to be aliased:
using ...types_pack = int, std::string, std::vector<unsigned char>;
After the type pack alias is defined, the effect of using it somewhere in
the code is completely identical to such of using the argument pack used
when defining a variadic template.
Usecases
1. Exposing variadic template arguments
It is a normal practice across STL template classes to expose their
arguments as member types. For example, std::string::value_type exposes an
(implicit) first argument of std::basic_string template,
std::istream::traits_type exposes the second one of std::basic_istream,
std::map<type1, type2>::allocator_type exposes the forth argument of
std::map and so on. At the same time, it is currently impossible to expose
the whole pack of parameters passed to std::tuple.
The benifits are as follows.
1. Currently, to refer to a 'tuple type containing all types from tuple1
plus all types from tuple2' one should use the following construct:
decltype(std::tuple_cat(tuple1(), tuple2()))
After introducing type pack aliases, this can be simplified so that one
does not need to use a type deduction mechanisms such as decltype and dummy
function calls:
std::tuple<tuple1::value_types..., tuple2::value_types...>
Here we assume that std::tuple<Types...>::value_types... is an alias for
Types....
2. Consider a parameter pack class which is implemeted using std::tuple
but exposes some additional functionality (e. g. serializing). It should be
constructable using both pre-built parameters tuple and explicit parameter
value list. Currently there are two workarounds to reach this goal:
1. Using tuple<parameter_types> as parameter pack template class
argument:
template <class ParameterTuple> class ParameterPack;
template <class ...Parameters>
class ParameterPack<std::tuple<Parameters...>>
{
public:
ParameterPack(const Parameters ...¶meters);
ParameterPack(const std::tuple<Parameters...> ¶meters);
};
ParameterPack<std::tuple<int, std::string>> parameters;
The disadvantage arising from such an approach is that we need to
explicitly refer to std::tuple each time we need to instantiate
ParameterPack class, as well as that we are potentially able to instantiate
it with a non-tuple argument which leads to non-obvious compilation errors.
2. Consider moving ParameterPack definition from previous code span
into a namespace called implementation. After that, one can alias it in the
main working namespace using the following syntax:
template <class ...Parameters> using ParameterPack =
implementation::ParameterPack<std::tuple<Parameters...>>;
ParameterPack<int, std::string> parameters;
The disadvantages of this approach are an overall complexity and the
usage of pack-unpack and pack-unpack-pack procedures to define the first
and the second constructors, respectfully (by `pack` we mean wrapping the
parameter pack by the tuple template; `unpack` is the reverse).
2. Aliasing function parameters
Consider a class hierarchy which contains a number of virtual calls:
class Base
{
public:
virtual int mount(const char *deviceId, const char *path, int accessRights)
= 0;
virtual int umount(const char *path) = 0;
};
class Direct : public Base
{
public:
virtual int mount(const char *deviceId, const char *path, int accessRights)
override
{
return system::mount(deviceId, path, accessRight);
}
virtual int umount(const char *path) override
{
return system::umount(path);
}
};
template <class MountHost>
class TryCatchWrapper : public Base
{
private:
MountHost *host;
public:
virtual int mount(const char *deviceId, const char *path, int accessRights)
override
{
try
{
return host->mount(deviceId, path, accessRights);
}
catch (...)
{
errno = ERR_EXCEPTION;
return -1;
}
}
virtual int umount(const char *path) override
{
try
{
return system::umount(path);
}
catch (...)
{
errno = ERR_EXCEPTION;
return -1;
}
}
};
class PointerImplemented
{
private:
class Implementation
{
public:
int mount(const char *deviceId, const char *path, int accessRights)
{
return system::mount(deviceId, path, accessRight);
}
int umount(const char *path)
{
return system::umount(path);
}
} *implementation;
public:
virtual int mount(const char *deviceId, const char *path, int accessRights)
override
{
return implementation->mount(deviceId, path, accessRight);
}
virtual int umount(const char *path) override
{
return implementation->umount(path);
}
};
class Stub : public Base
{
public:
virtual int mount(const char*, const char*, int) override
{
return 0;
}
virtual int umount(const char*) override
{
return 0;
}
};
In complex projects, there is a tendency to change such calls' signatures
from time to time, which requires full repository review as only the full
rebuild can guarantee that all invocations were modified. Also, note that
Stub, TryCatchWrapper and PointerImplemeted classes do not utilize any
parameter by themselves but nevertheless need these to be corrected.
Now imagine that we introduce aliases for the parameters of these
functions. Our code can now be re-formatted as follows:
class Base
{
public:
using ...mount_parameters = const char* /*deviceId*/, const char* /*path*/,
int /*accessRights*/;
using ...umount_parameters = const char* /*path*/;
virtual int mount(mount_parameters...) = 0;
virtual int umount(umount_parameters...) = 0;
};
class Direct : public Base
{
public:
virtual int mount(const char *deviceId, const char *path, int accessRights)
override
{
return system::mount(deviceId, path, accessRight);
}
virtual int umount(const char *path) override
{
return system::umount(path);
}
};
template <class MountHost>
class TryCatchWrapper : public Base
{
private:
MountHost *host;
public:
virtual int mount(mount_parameters ...parameters) override
{
try
{
return host->mount(parameters...);
}
catch (...)
{
errno = ERR_EXCEPTION;
return -1;
}
}
virtual int umount(umount_parameters ...parameters) override
{
try
{
return system::umount(parameters...);
}
catch (...)
{
errno = ERR_EXCEPTION;
return -1;
}
}
};
class PointerImplemented
{
private:
class Implementation
{
public:
int mount(const char *deviceId, const char *path, int accessRights)
{
return system::mount(deviceId, path, accessRight);
}
int umount(const char *path)
{
return system::umount(path);
}
} *implementation;
public:
virtual int mount(mount_parameters ...parameters) override
{
return implementation->mount(parameters);
}
virtual int umount(umount_parameters ...parameters) override
{
return implementation->umount(parameters...);
}
};
class Stub : public Base
{
public:
virtual int mount(mount_parameters...) override
{
return 0;
}
virtual int umount(umount_parameters...) override
{
return 0;
}
};
Though it doesn't look simplier, it is now far more supportable as no stubs
or wrappers should now be reviewed when Base::mount's and Base::umount's
signatures change. Instead, one should only refactor the places which are
actually using the parameters passed which ensures that no place that
should be checked will be skipped due to the usage of the newly introduced
aliasing concept.
3. Base class constructor parameters in inheritance chains
Complex projects tend to get origin to complex inheritance chains where
constructor parameters get transferred from child class to its parent.
Though naming all the constructor parameters explicitly has the advantage
that one can always check the signature with ease, overall code weight gets
increased (and again, the supportability degrades as we need to review all
child classes when baseclass'es parameters change). The below example
illustrates this:
class Object
{
public:
Object() {}
};
class Window : parent Object
{
public:
Window(Window *parent) : Object(), m_parent(parent) {}
};
class View : public Window
{
public:
View(Window *parent, int left, int top, int width, int height) :
Window(parent), m_left(left), m_top(top), m_width(width), m_height(height)
{}
};
class Button : public View
{
public:
Button(Window *parent, int left, int top, int width, int height, const char
*caption) : View(parent, left, top, width, height), m_caption(caption) {}
};
Now imagine each class aliasing its constructor parameters:
class Object
{
public:
using ...constructor_parameters = ;
Object() {}
};
class Window : parent Object
{
public:
using ...constructor_parameters = Object::constructor_parameters, Window*;
Window(Object::constructor_parameters ...parent_parameters, Window *parent)
: Object(parent_parameters...), m_parent(parent) {}
};
class View : public Window
{
public:
using ...constructor_parameters = Window::constructor_parameters, int, int,
int, int;
View(Window::constructor_parameters ...parent_parameters, int left, int
top, int width, int height) : Window(parent_parameters...), m_left(left),
m_top(top), m_width(width), m_height(height) {}
};
class Button : public View
{
public:
using ...constructor_parameters = View::constructor_parameters, const char*;
Button(View::constructor_parameters ...parent_parameters, const char
*caption) : View(parent_parameters...), m_caption(caption) {}
};
Though the overall number of lines increased slightly, the code becomes
more flexible as we can now change constructor arguments on any level
without the neccessity to review all the intermediate classes (but of
course we still need to change argument lists when we create objects that
inherit from changed classes).
Furthermore, imagine that at some point the inheritance should be done via
proxy class rather than directly for some reason:
template <class Parent, class Traits>
class Proxy : public Parent
{
public:
typedef Traits traits_type;
Proxy(Parent::constructor_parameters ...parent_parameters) :
Parent(parent_parameters...) {}
};
class View : public Proxy<Window, TraitsType>
{
public:
using ...constructor_parameters = Proxy<Window,
TraitsType>::constructor_parameters, int, int, int, int;
View(Proxy<Window, TraitsType>::constructor_parameters
....parent_parameters, int left, int top, int width, int height) :
Proxy<Window, TraitsType>(parent_parameters...), m_left(left), m_top(top),
m_width(width), m_height(height) {}
};
We now have a strict and explicit typization for Proxy's constructor
parameters while otherwise we would need it to be a variadic template
function.
Conclusion
This proposal does not introduce any functionality that can't be reached
using existing techniques. Nevertheless, it addresses few issues that are
unrelated which proves that the solution is of a generic kind rather than
an in-place fix. The syntax proposed seems natural and lies in line with
common C++ practices. Furthermore, no existing functionality is broken if
such a construct gets approved as both 'using name = ;' and commas after
'using' keyword are currently considered syntax violations.
Discussion
Any comments are highly appreciated. =)
--
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/4afe7fc3-3c43-4253-81ca-86ee7ba15e70%40isocpp.org.
------=_Part_3581_281892888.1462811793823
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><font size=3D"6">Definition</font></div>There is a pr=
oposal to extend C++ language core so that the developer would be able to i=
ntroduce aliases for the packs of types rather than for single type. The me=
aning for `the pack of types` is same as when defining variadic templates. =
The proposed syntax is as follows:<div><div class=3D"prettyprint" style=3D"=
border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-col=
or: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><div class=3D"subprettyprint">template <class ...Pack></div><=
div class=3D"subprettyprint">struct Packed</div><div class=3D"subprettyprin=
t">{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" styl=
e=3D"white-space:pre"> </span>using ...packed_type =3D Pack...;</div><div c=
lass=3D"subprettyprint">};</div></div></code></div>An alternative syntax sh=
ould allow it to explicitly specify the list of types to be aliased:</div><=
div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187=
); word-wrap: break-word; background-color: rgb(250, 250, 250);"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><font color=3D"#666600">usi=
ng ...types_pack =3D int, std::string, std::vector<unsigned char>;</f=
ont><br></div></code></div>After the type pack alias is defined, the effect=
of using it somewhere in the code is completely identical to such of using=
the argument pack used when defining a variadic template.</div><div><br></=
div><div><font size=3D"6">Usecases</font></div><div><font size=3D"4">1. Exp=
osing variadic template arguments</font></div><div><font size=3D"2">It is a=
normal practice across STL template classes to expose their arguments as m=
ember types. For example, std::string::value_type exposes an (implicit) fir=
st argument of std::basic_string template, std::istream::traits_type expose=
s the second one of std::basic_istream, std::map<type1, type2>::alloc=
ator_type exposes the forth argument of std::map and so on. At the same tim=
e, it is currently impossible to expose the whole pack of parameters passed=
to std::tuple.</font></div><div><font size=3D"2">The benifits are as follo=
ws.</font></div><div><ol><li><font size=3D"2"><span style=3D"line-height: n=
ormal;">Currently, to refer to a 'tuple type containing all types from =
tuple1 plus all types from tuple2' one should use the following constru=
ct:</span><br><span style=3D"line-height: normal;"><div class=3D"prettyprin=
t" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; ba=
ckground-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">decltype</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(std::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">tup=
le_cat</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">tuple1</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> tuple2</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">()))</span></div></code></d=
iv>After introducing type pack aliases, this can be simplified so that one =
does not need to use a type deduction mechanisms such as decltype and dummy=
function calls:<br></span><div class=3D"prettyprint" style=3D"border: 1px =
solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250,=
250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><fon=
t color=3D"#666600">std::tuple<tuple1::value_types..., tuple2::value_typ=
es...></font><br></div></code></div>Here we assume that std::tuple<Ty=
pes...>::value_types... is an alias for Types....</font></li><li><font s=
ize=3D"2">Consider a parameter pack class which is implemeted using std::tu=
ple but exposes some additional functionality (e. g. serializing). It shoul=
d be constructable using both pre-built parameters tuple and explicit param=
eter value list. Currently there are two workarounds to reach this goal:</f=
ont></li><ol><li><font size=3D"2">Using tuple<parameter_types> as par=
ameter pack template class argument:<br><div class=3D"prettyprint" style=3D=
"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-co=
lor: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subpret=
typrint"><div class=3D"subprettyprint">template <class ParameterTuple>=
; class ParameterPack;</div><div class=3D"subprettyprint">template <clas=
s ...Parameters></div><div class=3D"subprettyprint">class ParameterPack&=
lt;std::tuple<Parameters...>></div><div class=3D"subprettyprint">{=
</div><div class=3D"subprettyprint">public:</div><div class=3D"subprettypri=
nt"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Parame=
terPack(const Parameters ...&parameters);</div><div class=3D"subprettyp=
rint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Para=
meterPack(const std::tuple<Parameters...> &parameters);</div><div=
class=3D"subprettyprint">};<br>ParameterPack<std::tuple<int, std::st=
ring>> parameters;<br></div></div></code></div>The disadvantage arisi=
ng from such an approach is that we need to explicitly refer to std::tuple =
each time we need to instantiate ParameterPack class, as well as that we ar=
e potentially able to instantiate it with a non-tuple argument which leads =
to non-obvious compilation errors.</font></li><li><font size=3D"2">Consider=
moving ParameterPack definition from previous code span into a namespace c=
alled implementation. After that, one can alias it in the main working name=
space using the following syntax:<br><div class=3D"prettyprint" style=3D"bo=
rder: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color=
: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><font color=3D"#666600">template <class ...Parameters> using Pa=
rameterPack =3D implementation::ParameterPack<std::tuple<Parameters..=
..>>;<br></font>ParameterPack<int, std::string> parameters;<br><=
/div></code></div>The disadvantages of this approach are an overall complex=
ity and the usage of pack-unpack and pack-unpack-pack procedures to define =
the first and the second constructors, respectfully (by `pack` we mean wrap=
ping the parameter pack by the tuple template; `unpack` is the reverse).</f=
ont></li></ol></ol><div><font size=3D"2"><span style=3D"line-height: 17px;"=
><br></span></font></div><div><span style=3D"line-height: 17px;"><font size=
=3D"4">2. Aliasing function parameters</font></span></div></div><div><span =
style=3D"line-height: 17px;"><font size=3D"2">Consider a class=C2=A0</font>=
</span><font size=3D"2"><span style=3D"line-height: 17px;">hierarchy which =
contains a number of virtual calls:</span></font></div><div><font size=3D"2=
"><span style=3D"line-height: 17px;"><div class=3D"prettyprint" style=3D"bo=
rder: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color=
: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><div class=3D"subprettyprint">class Base</div><div class=3D"subpretty=
print">{</div><div class=3D"subprettyprint">public:</div><div class=3D"subp=
rettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </spa=
n>virtual int mount(const char *deviceId, const char *path, int accessRight=
s) =3D 0;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>virtual int umount(const char *path) =3D=
0;</div><div class=3D"subprettyprint">};</div><div class=3D"subprettyprint=
">class Direct : public Base</div><div class=3D"subprettyprint">{</div><div=
class=3D"subprettyprint">public:</div><div class=3D"subprettyprint"><span =
class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>virtual int moun=
t(const char *deviceId, const char *path, int accessRights) override</div><=
div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-=
space:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"Appl=
e-tab-span" style=3D"white-space:pre"> </span>return system::mount(deviceI=
d, path, accessRight);</div><div class=3D"subprettyprint"><span class=3D"Ap=
ple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"subpre=
ttyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
virtual int umount(const char *path) override</div><div class=3D"subprettyp=
rint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</d=
iv><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"wh=
ite-space:pre"> </span>return system::umount(path);</div><div class=3D"sub=
prettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>}</div><div class=3D"subprettyprint">};</div><div class=3D"subprettyprin=
t">template <class MountHost></div><div class=3D"subprettyprint">clas=
s TryCatchWrapper : public Base</div><div class=3D"subprettyprint">{</div><=
div class=3D"subprettyprint">private:</div><div class=3D"subprettyprint"><s=
pan class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>MountHost *h=
ost;</div><div class=3D"subprettyprint">public:</div><div class=3D"subprett=
yprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>vi=
rtual int mount(const char *deviceId, const char *path, int accessRights) o=
verride</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" s=
tyle=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint"><span=
class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>try</div><div =
class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-spac=
e:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"Apple-t=
ab-span" style=3D"white-space:pre"> </span>return host->mount(deviceId=
, path, accessRights);</div><div class=3D"subprettyprint"><span class=3D"Ap=
ple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"subpr=
ettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </spa=
n>catch (...)</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-s=
pan" style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint=
"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>errno =
=3D ERR_EXCEPTION;</div><div class=3D"subprettyprint"><span class=3D"Apple-=
tab-span" style=3D"white-space:pre"> </span>return -1;</div><div class=3D=
"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> =
</span>}</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint"><sp=
an class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>virtual int u=
mount(const char *path) override</div><div class=3D"subprettyprint"><span c=
lass=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>try</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-=
span" style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprin=
t"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>retur=
n system::umount(path);</div><div class=3D"subprettyprint"><span class=3D"A=
pple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"subp=
rettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>catch (...)</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-=
span" style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprin=
t"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>errno=
=3D ERR_EXCEPTION;</div><div class=3D"subprettyprint"><span class=3D"Apple=
-tab-span" style=3D"white-space:pre"> </span>return -1;</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>}</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-sp=
an" style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint">=
};</div><div class=3D"subprettyprint">class PointerImplemented</div><div cl=
ass=3D"subprettyprint">{</div><div class=3D"subprettyprint">private:</div><=
div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-=
space:pre"> </span>class Implementation</div><div class=3D"subprettyprint">=
<span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</div><di=
v class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-sp=
ace:pre"> </span>public:</div><div class=3D"subprettyprint"><span class=3D"=
Apple-tab-span" style=3D"white-space:pre"> </span>int mount(const char *de=
viceId, const char *path, int accessRights)</div><div class=3D"subprettypri=
nt"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</di=
v><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"whi=
te-space:pre"> </span>return system::mount(deviceId, path, accessRight);<=
/div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"=
white-space:pre"> </span>}</div><div class=3D"subprettyprint"><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>int umount(const cha=
r *path)</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" =
style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint"><sp=
an class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>return syst=
em::umount(path);</div><div class=3D"subprettyprint"><span class=3D"Apple-t=
ab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyp=
rint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>} *i=
mplementation;</div><div class=3D"subprettyprint">public:</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>virtual int mount(const char *deviceId, const char *path, int acc=
essRights) override</div><div class=3D"subprettyprint"><span class=3D"Apple=
-tab-span" style=3D"white-space:pre"> </span>{</div><div class=3D"subpretty=
print"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>re=
turn implementation->mount(deviceId, path, accessRight);</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>}</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-spa=
n" style=3D"white-space:pre"> </span>virtual int umount(const char *path) o=
verride</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" s=
tyle=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint"><span=
class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>return impleme=
ntation->umount(path);</div><div class=3D"subprettyprint"><span class=3D=
"Apple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"sub=
prettyprint">};</div><div class=3D"subprettyprint">class Stub : public Base=
</div><div class=3D"subprettyprint">{</div><div class=3D"subprettyprint">pu=
blic:</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" sty=
le=3D"white-space:pre"> </span>virtual int mount(const char*, const char*, =
int) override</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-s=
pan" style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint"=
><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>return 0=
;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=
=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint"><span cla=
ss=3D"Apple-tab-span" style=3D"white-space:pre"> </span>virtual int umount(=
const char*) override</div><div class=3D"subprettyprint"><span class=3D"App=
le-tab-span" style=3D"white-space:pre"> </span>{</div><div class=3D"subpret=
typrint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
return 0;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint">};<=
/div></div></code></div>In complex projects, there is a tendency to change =
such calls' signatures from time to time, which requires full repositor=
y review as only the full rebuild can guarantee that all invocations were m=
odified. Also, note that Stub, TryCatchWrapper and PointerImplemeted classe=
s do not utilize any parameter by themselves but nevertheless need these to=
be corrected.</span></font></div><div>Now imagine that we introduce aliase=
s for the parameters of these functions. Our code can now be re-formatted a=
s follows:</div><div><div class=3D"prettyprint" style=3D"border: 1px solid =
rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250, 250, =
250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><div class=
=3D"subprettyprint">class Base</div><div class=3D"subprettyprint">{</div><d=
iv class=3D"subprettyprint">public:</div><div class=3D"subprettyprint"><spa=
n class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>using ...mount=
_parameters =3D const char* /*deviceId*/, const char* /*path*/, int /*acces=
sRights*/;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span=
" style=3D"white-space:pre"> </span>using ...umount_parameters =3D const ch=
ar* /*path*/;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-s=
pan" style=3D"white-space:pre"> </span>virtual int mount(mount_parameters..=
..) =3D 0;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>virtual int umount(umount_parameters...)=
=3D 0;</div><div class=3D"subprettyprint">};</div><div class=3D"subprettyp=
rint">class Direct : public Base</div><div class=3D"subprettyprint">{</div>=
<div class=3D"subprettyprint">public:</div><div class=3D"subprettyprint"><s=
pan class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>virtual int =
mount(const char *deviceId, const char *path, int accessRights) override</d=
iv><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"wh=
ite-space:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"=
Apple-tab-span" style=3D"white-space:pre"> </span>return system::mount(dev=
iceId, path, accessRight);</div><div class=3D"subprettyprint"><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"=
subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> <=
/span>virtual int umount(const char *path) override</div><div class=3D"subp=
rettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </spa=
n>{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=
=3D"white-space:pre"> </span>return system::umount(path);</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>}</div><div class=3D"subprettyprint">};</div><div class=3D"subpre=
ttyprint">template <class MountHost></div><div class=3D"subprettyprin=
t">class TryCatchWrapper : public Base</div><div class=3D"subprettyprint">{=
</div><div class=3D"subprettyprint">private:</div><div class=3D"subprettypr=
int"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Mount=
Host *host;</div><div class=3D"subprettyprint">public:</div><div class=3D"s=
ubprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </=
span>virtual int mount(mount_parameters ...parameters) override</div><div c=
lass=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space=
:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab=
-span" style=3D"white-space:pre"> </span>try</div><div class=3D"subprettyp=
rint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</=
div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"w=
hite-space:pre"> </span>return host->mount(parameters...);</div><div c=
lass=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space=
:pre"> </span>}</div><div class=3D"subprettyprint"><span class=3D"Apple-ta=
b-span" style=3D"white-space:pre"> </span>catch (...)</div><div class=3D"s=
ubprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> <=
/span>{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" s=
tyle=3D"white-space:pre"> </span>errno =3D ERR_EXCEPTION;</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>return -1;</div><div class=3D"subprettyprint"><span class=3D"Ap=
ple-tab-span" style=3D"white-space:pre"> </span>}</div><div class=3D"subpr=
ettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span=
>}</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=
=3D"white-space:pre"> </span>virtual int umount(umount_parameters ...parame=
ters) override</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-=
span" style=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint=
"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>try</di=
v><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"whi=
te-space:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"=
Apple-tab-span" style=3D"white-space:pre"> </span>return system::umount(p=
arameters...);</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-=
span" style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprin=
t"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>catch =
(...)</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" sty=
le=3D"white-space:pre"> </span>{</div><div class=3D"subprettyprint"><span =
class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>errno =3D ERR_=
EXCEPTION;</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span=
" style=3D"white-space:pre"> </span>return -1;</div><div class=3D"subpret=
typrint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
}</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=
=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint">};</div><=
div class=3D"subprettyprint">class PointerImplemented</div><div class=3D"su=
bprettyprint">{</div><div class=3D"subprettyprint">private:</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>class Implementation</div><div class=3D"subprettyprint"><span cla=
ss=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>public:</div><div class=3D"subprettyprint"><span class=3D"Apple-t=
ab-span" style=3D"white-space:pre"> </span>int mount(const char *deviceId,=
const char *path, int accessRights)</div><div class=3D"subprettyprint"><sp=
an class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</div><div =
class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-spac=
e:pre"> </span>return system::mount(deviceId, path, accessRight);</div><d=
iv class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-s=
pace:pre"> </span>}</div><div class=3D"subprettyprint"><span class=3D"Appl=
e-tab-span" style=3D"white-space:pre"> </span>int umount(const char *path)=
</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D=
"white-space:pre"> </span>{</div><div class=3D"subprettyprint"><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>return system::umou=
nt(path);</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint"><s=
pan class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>} *implement=
ation;</div><div class=3D"subprettyprint">public:</div><div class=3D"subpre=
ttyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
virtual int mount(mount_parameters ...parameters) override</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-spa=
n" style=3D"white-space:pre"> </span>return implementation->mount(param=
eters);</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" s=
tyle=3D"white-space:pre"> </span>}</div><div class=3D"subprettyprint"><span=
class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>virtual int umo=
unt(umount_parameters ...parameters) override</div><div class=3D"subprettyp=
rint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>{</d=
iv><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"wh=
ite-space:pre"> </span>return implementation->umount(parameters...);</d=
iv><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"wh=
ite-space:pre"> </span>}</div><div class=3D"subprettyprint">};</div><div cl=
ass=3D"subprettyprint">class Stub : public Base</div><div class=3D"subprett=
yprint">{</div><div class=3D"subprettyprint">public:</div><div class=3D"sub=
prettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>virtual int mount(mount_parameters...) override</div><div class=3D"subpr=
ettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span=
>{</div><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=
=3D"white-space:pre"> </span>return 0;</div><div class=3D"subprettyprint">=
<span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</div><di=
v class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-sp=
ace:pre"> </span>virtual int umount(umount_parameters...) override</div><di=
v class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-sp=
ace:pre"> </span>{</div><div class=3D"subprettyprint"><span class=3D"Apple-=
tab-span" style=3D"white-space:pre"> </span>return 0;</div><div class=3D"s=
ubprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </=
span>}</div><div class=3D"subprettyprint">};</div></div></code></div>Though=
it doesn't look simplier, it is now far more supportable as no stubs o=
r wrappers should now be reviewed when Base::mount's and Base::umount&#=
39;s signatures change. Instead, one should only refactor the places which =
are actually using the parameters passed which ensures that no place that s=
hould be checked will be skipped due to the usage of the newly introduced a=
liasing concept.</div><div><br></div><div><br></div><div><span style=3D"lin=
e-height: 17px;"><font size=3D"4">3. Base class constructor parameters in i=
nheritance chains</font></span></div><div><span style=3D"line-height: 17px;=
"><font size=3D"2">Complex projects tend to get origin to complex inheritan=
ce chains where constructor parameters get transferred from child class to =
its parent. Though naming all the constructor parameters explicitly has the=
advantage that one can always check the signature with ease, overall code =
weight gets increased (and again, the supportability degrades as we need to=
review all child classes when baseclass'es parameters change). The bel=
ow example illustrates this:</font></span></div><div><span style=3D"line-he=
ight: 17px;"><font size=3D"2"><div class=3D"prettyprint" style=3D"border: 1=
px solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(2=
50, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><=
div class=3D"subprettyprint">class Object</div><div class=3D"subprettyprint=
">{</div><div class=3D"subprettyprint">public:</div><div class=3D"subpretty=
print"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Obj=
ect() {}</div><div class=3D"subprettyprint">};</div><div class=3D"subpretty=
print">class Window : parent Object</div><div class=3D"subprettyprint"><spa=
n style=3D"font-family: Arial, Helvetica, sans-serif;">{</span><br></div><d=
iv class=3D"subprettyprint">public:</div><div class=3D"subprettyprint"><spa=
n class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Window(Window =
*parent) : Object(), m_parent(parent) {}</div><div class=3D"subprettyprint"=
>};</div><div class=3D"subprettyprint">class View : public Window</div><div=
class=3D"subprettyprint">{</div><div class=3D"subprettyprint">public:</div=
><div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"whit=
e-space:pre"> </span>View(Window *parent, int left, int top, int width, int=
height) : Window(parent), m_left(left), m_top(top), m_width(width), m_heig=
ht(height) {}</div><div class=3D"subprettyprint">};</div><div class=3D"subp=
rettyprint">class Button : public View</div><div class=3D"subprettyprint">{=
</div><div class=3D"subprettyprint">public:</div><div class=3D"subprettypri=
nt"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Button=
(Window *parent, int left, int top, int width, int height, const char *capt=
ion) : View(parent, left, top, width, height), m_caption(caption) {}</div><=
div class=3D"subprettyprint">};</div></div></code></div>Now imagine each cl=
ass aliasing its constructor parameters:</font></span></div><div><span styl=
e=3D"line-height: 17px;"><font size=3D"2"><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><div class=3D"subprettyprint">class Object</div><div class=3D"s=
ubprettyprint">{</div><div class=3D"subprettyprint">public:</div><div class=
=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre=
"> </span>using ...constructor_parameters =3D ;</div><div class=3D"subprett=
yprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Ob=
ject() {}</div><div class=3D"subprettyprint">};</div><div class=3D"subprett=
yprint">class Window : parent Object</div><div class=3D"subprettyprint">{</=
div><div class=3D"subprettyprint">public:</div><div class=3D"subprettyprint=
"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>using ..=
..constructor_parameters =3D Object::constructor_parameters, Window*;</div><=
div class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-=
space:pre"> </span>Window(Object::constructor_parameters ...parent_paramete=
rs, Window *parent) : Object(parent_parameters...), m_parent(parent) {}</di=
v><div class=3D"subprettyprint">};</div><div class=3D"subprettyprint">class=
View : public Window</div><div class=3D"subprettyprint">{</div><div class=
=3D"subprettyprint">public:</div><div class=3D"subprettyprint"><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>using ...constructor_=
parameters =3D Window::constructor_parameters, int, int, int, int;</div><di=
v class=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-sp=
ace:pre"> </span>View(Window::constructor_parameters ...parent_parameters, =
int left, int top, int width, int height) : Window(parent_parameters...), m=
_left(left), m_top(top), m_width(width), m_height(height) {}</div><div clas=
s=3D"subprettyprint">};</div><div class=3D"subprettyprint">class Button : p=
ublic View</div><div class=3D"subprettyprint">{</div><div class=3D"subprett=
yprint">public:</div><div class=3D"subprettyprint"><span class=3D"Apple-tab=
-span" style=3D"white-space:pre"> </span>using ...constructor_parameters =
=3D View::constructor_parameters, const char*;</div><div class=3D"subpretty=
print"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>But=
ton(View::constructor_parameters ...parent_parameters, const char *caption)=
: View(parent_parameters...), m_caption(caption) {}</div><div class=3D"sub=
prettyprint">};</div></div></code></div>Though the overall number of lines =
increased slightly, the code becomes more flexible as we can now change con=
structor arguments on any level without the neccessity to review all the in=
termediate classes (but of course we still need to change argument lists wh=
en we create objects that inherit from changed classes).</font></span></div=
><div><span style=3D"line-height: 17px;"><font size=3D"2">Furthermore, imag=
ine that at some point the inheritance should be done via proxy class rathe=
r than directly=C2=A0</font></span><span style=3D"font-size: small; line-he=
ight: 17px;">for some reason:</span></div><div><span style=3D"font-size: sm=
all; line-height: 17px;"><div class=3D"prettyprint" style=3D"border: 1px so=
lid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250, 2=
50, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><div c=
lass=3D"subprettyprint">template <class Parent, class Traits></div><d=
iv class=3D"subprettyprint">class Proxy : public Parent</div><div class=3D"=
subprettyprint">{</div><div class=3D"subprettyprint">public:</div><div clas=
s=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pr=
e"> </span>typedef Traits traits_type;</div><div class=3D"subprettyprint"><=
span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Proxy(Paren=
t::constructor_parameters ...parent_parameters) : Parent(parent_parameters.=
...) {}</div><div class=3D"subprettyprint">};</div><div class=3D"subprettypr=
int">class View : public Proxy<Window, TraitsType></div><div class=3D=
"subprettyprint">{</div><div class=3D"subprettyprint">public:</div><div cla=
ss=3D"subprettyprint"><span class=3D"Apple-tab-span" style=3D"white-space:p=
re"> </span>using ...constructor_parameters =3D Proxy<Window, TraitsType=
>::constructor_parameters, int, int, int, int;</div><div class=3D"subpre=
ttyprint"><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
View(Proxy<Window, TraitsType>::constructor_parameters ...parent_para=
meters, int left, int top, int width, int height) : Proxy<Window, Traits=
Type>(parent_parameters...), m_left(left), m_top(top), m_width(width), m=
_height(height) {}</div><div class=3D"subprettyprint">};</div></div></code>=
</div>We now have a strict and explicit typization for Proxy's construc=
tor parameters while otherwise we would need it to be a variadic template f=
unction.<br><br></span></div><div><span style=3D"line-height: 17px;"><font =
size=3D"6">Conclusion</font></span></div><div><span style=3D"line-height: 1=
7px;"><font size=3D"2">This proposal does not introduce any functionality t=
hat can't be reached using existing techniques. Nevertheless, it addres=
ses few issues that are unrelated which proves that the solution is of a ge=
neric kind rather than an in-place fix. The syntax proposed seems natural a=
nd lies in line with common C++ practices. Furthermore, no existing functio=
nality is broken if such a construct gets approved as both 'using name =
=3D ;' and commas after 'using' keyword are currently considere=
d syntax violations.</font></span></div><div><span style=3D"line-height: 17=
px;"><font size=3D"2"><br></font></span></div><div><span style=3D"line-heig=
ht: 17px;"><font size=3D"6">Discussion</font></span></div><div><span style=
=3D"line-height: 17px;"><font size=3D"2">Any comments are highly appreciate=
d. =3D)</font></span></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/4afe7fc3-3c43-4253-81ca-86ee7ba15e70%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4afe7fc3-3c43-4253-81ca-86ee7ba15e70=
%40isocpp.org</a>.<br />
------=_Part_3581_281892888.1462811793823--
------=_Part_3580_39015991.1462811793821--
.