Topic: extend_cast<T> : extending interfaces safely without


Author: Tahsin Mazumdar <tahsin.tanzim@gmail.com>
Date: Tue, 25 Jul 2017 17:47:38 -0700 (PDT)
Raw View
------=_Part_4662_1401742107.1501030058405
Content-Type: multipart/alternative;
 boundary="----=_Part_4663_978283217.1501030058406"

------=_Part_4663_978283217.1501030058406
Content-Type: text/plain; charset="UTF-8"

Currently there is no easy way to extend class interfaces and still remain
compatible with instances of the older interface. In certain cases, this
might not be all that difficult to do if we ensure that the binary layout
does not change across interfaces.

Let's say as an arbitrary example we want to extend the std::vector
interface, we could do the following:

template <typename T>
class extended_vector : public std::vector<T>
{
public:
  template <typename... Args>
  extended_vector(Args&&... args): std::vector<T>(std::forward<Args>(args
)...) {}

  auto accumulate(T init)
  {
    return std::accumulate(this->begin(), this->end(), init);
  }

};

Note that since we have not added any member variables to extended_vector,
the binary layout of the two classes should be identical. Thus, at least in
concept, I should be able to use instances of either class interchangeably
with the other's interface. However this is not the case: if I only have an
instance of std::vector<T>, there is no standard way to "treat" that
instance like an extended_vector<T> and take advantage of its extended
interface.

std::vector<T> some_external_function_returns_vector();

auto a = some_external_function_returns_vector();
// ^ Can't use extended_vector<T>::accumulate on this
// Instead we have to use a free function:
std::accumulate(begin(a), end(a), 2);

The standard library does this to a great extent for extending interfaces
(i.e. writing free functions). But this is not an ideal solution in my
opinion as it breaks encapsulation to a certain degree - related data and
functions should be coupled together. std::accumulate operates primarily on
the state defined inside of vector; to have them be separate forces us to
pass in every member needed individually (e.g. begin() and end()) and
results in cumbersome and longer syntax as we see with the <algorithm>
library. This also discourages the use of classes and inheritance entirely
when we are looking to scale up. From a design perspective, it forces
developers to adopt a mix of C style (use of free functions) and
Object-Oriented C++ style (classes and member functions) for a relatively
mundane reason.

There might be another solution, simply to cast the std::vector as an
extended_vector. Though this also has its problems currently:

std::vector<int> A { 1,2,3,4};
auto const& B = static_cast<extended_vector<int>&>(A);
B.accumulate(2);



This code compiles and works as expected. However this falls under the
umbrella of undefined behavior, and I would hardly use this in production.
Casting in this case might be safe because the binary layout of the two
classes are identical, but if someone were to add any state or member
variables to extended_vector in the future, the code would still compile
only to fail in unexpected ways down the line:


template <typename T>
class bad_vector : public std::vector<T>
{
  int a;  // <-- additional state: will no longer have the same layout as
std::vector
public:
  template <typename... Args>
  bad_vector(Args&&... args): std::vector<T>(std::forward<Args>(args)...) {}

  auto accumulate(T init)
  {
    return std::accumulate(this->begin(), this->end(), a + init);
  }
};

std::vector<int> A { 1,2,3,4};
auto const& B = static_cast<bad_vector<int>&>(A);  // still compiles
B.accumulate(2);   // UB: Bad!



To get around this problem I wonder if it might be possible to introduce a
new form of cast that simply does a compile-time check to verify that the
binary layout is the same. Essentially it could give a compile-error if the
binary layouts of the classes are not equivalent and only compile if we are
certain that the downcast conversion is safe. It could be as simple as
checking that the extended interface does not define any additional state.
If there is no additional state, only member functions (or possibly
statics), any added functionality would live outside of the instance giving
us no reason to expect any undefined behavior if we were to cast it to the
newer interface:


std::vector<int> A { 1,2,3,4};
auto& B = extend_cast<extended_vector<int>&>(A);  // OK; same binary layout
B.accumulate(2);  // should be safe to do this now

auto& C = extend_cast<bad_vector<int>&>(A); // compile error; bad_vector is
not binary compatible with std::vector
C.accumulate(2); // not safe, but hopefully will never compile


This feature would allow us to extend interfaces in C++ style, enabling
better encapsulation and readability and encourage the use of classes and
inheritance (and as a result better code reuse through access to
'protected' members of the base, which we would not get through free
functions).

Things might get a bit more complicated when virtual functions come into
play - I'm not entirely certain if this is still guaranteed to work if
virtual methods or overrides are added, but even if this only applies to
non-polymorphic classes I think this might be useful when its pretty common
practice to extend external interfaces, and having to write free functions
all the time is less than ideal.

[Apologies in advance if something like this has already been proposed or
is in this works; I'm not aware of anything as such at the time of writing.]

--
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/837a9764-71af-46e8-8594-f6b78f4c3c93%40isocpp.org.

------=_Part_4663_978283217.1501030058406
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Currently there is no easy way to extend class interfaces =
and still remain compatible with instances of the older interface. In certa=
in cases, this might not be all that difficult to do if we ensure that the =
binary layout does not change across interfaces.<br><br>Let&#39;s say as an=
 arbitrary example we want to extend the std::vector interface, we could do=
 the following:<br><br><div style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; o=
verflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprint=
"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"style=
d-by-prettify">template</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">ty=
pename</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">class</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> extended_vector </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=
: #008;" class=3D"styled-by-prettify">public</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">vector</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">public</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">template</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">typename</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">...</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pr=
ettify">Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 extended_vector</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #606;" class=3D"styled-by-prettif=
y">Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&am=
p;&amp;...</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">):</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&gt;(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">forward</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-prettify">=
Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;(<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">args</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: #660;" class=3D"styled-by-prettify">{}</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br><br>=C2=A0 </span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> accumulate</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">T init</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>=C2=A0 </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">acc=
umulate</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">this</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">-&gt;</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">this</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">-&gt;</span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">end</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">(),</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> init</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">};</span></div></=
code></div><br>Note that since we have not added any member variables to ex=
tended_vector, the binary layout of the two classes should be identical. Th=
us, at least in concept, I should be able to use instances of either class =
interchangeably with the other&#39;s interface. However this is not the cas=
e: if I only have an instance of std::vector&lt;T&gt;, there is no standard=
 way to &quot;treat&quot; that instance like an extended_vector&lt;T&gt; an=
d take advantage of its extended interface.<br><br><div style=3D"background=
-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style:=
 solid; border-width: 1px; overflow-wrap: break-word;" class=3D"prettyprint=
"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"=
color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">vector</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> some_external_function_returns_vector</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> a </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> some_external_function_returns_vector</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" class=3D"s=
tyled-by-prettify">// ^ Can&#39;t use extended_vector&lt;T&gt;::accumulate =
on this</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
></span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Instea=
d we have to use a free function:</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">accumulate</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">begin</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">),</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">end</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"style=
d-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">2<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span></=
div></code></div><br>The standard library does this to a great extent for e=
xtending interfaces (i.e. writing free functions). But this is not an ideal=
 solution in my opinion as it breaks encapsulation=20
to a certain degree - related data and functions should be coupled=20
together. std::accumulate operates primarily on the state defined inside of=
 vector; to have them be separate forces us to pass in every member needed =
individually (e.g. begin() and
 end()) and results in cumbersome and longer syntax as we see with the=20
&lt;algorithm&gt; library. This also discourages the use of classes and inh=
eritance entirely when we
 are looking to scale up. From a design perspective, it forces developers t=
o adopt a mix of C style (use of free functions) and Object-Oriented C++ st=
yle (classes and member functions) for a relatively mundane reason.<br><br>=
There might be another solution, simply to cast the std::vector as an exten=
ded_vector. Though this also has its problems currently:<br><br><div style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; overflow-wrap: break-word;" class=
=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettyprint">=
<span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"colo=
r: #080;" class=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> A </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">1</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #066;" class=3D"styled-by-prettify">2</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><spa=
n style=3D"color: #066;" class=3D"styled-by-prettify">3</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #066;" class=3D"styled-by-prettify">4</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"style=
d-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
const</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> B </span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">static_cast</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify">extended_vector</span><span style=3D"c=
olor: #080;" class=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&amp;&gt;(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">A</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>B</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">accumulate</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span=
></div></code></div><br><br>This code compiles and works as expected. Howev=
er this falls under the umbrella of undefined behavior, and I would hardly =
use this in production. Casting in this case might be safe because the bina=
ry layout of the two classes are identical, but if someone were to add any =
state or member variables to extended_vector in the future, the code would =
still compile only to fail in unexpected ways down the line:<br><br><br><di=
v style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187=
, 187); border-style: solid; border-width: 1px; overflow-wrap: break-word;"=
 class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #008;" class=3D"styled-by-prettify">template</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> bad_vector </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">public</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">vector</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> a</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> =C2=A0</span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// &lt;-- additional state: will no longer have the same layout as std::vec=
tor</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">public</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">template</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">typename</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: #606;" class=3D"style=
d-by-prettify">Args</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>=C2=A0 bad_vector</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #606;" class=3D"styled-by-prett=
ify">Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
amp;&amp;...</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">):<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">&gt;(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">forward</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-prettif=
y">Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt=
;(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">args</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">)...)</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{}</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br><br>=C2=A0 </span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> accumulate</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">T init</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>=C2=A0 </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a=
ccumulate</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">this</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">-&gt;</span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">this</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">-&gt;</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">end</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">(),</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> a </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">+</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> init<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br><br>std</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> A </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">=
1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">2</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #066;" class=3D"styled-by-prettify">3</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #066;" class=3D=
"styled-by-prettify">4</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">au=
to</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> B </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">static_cast</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">bad_vector</span><span style=3D"color: #080;" class=3D"=
styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">&amp;&gt;(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">A</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> =C2=A0</span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>// still compiles</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br>B</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">accumu=
late</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</spa=
n><span style=3D"color: #066;" class=3D"styled-by-prettify">2</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> =C2=A0 </span><span style=3D"co=
lor: #800;" class=3D"styled-by-prettify">// UB: Bad!</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span></div></code></div=
><br><br>To get around this problem I wonder if it might be possible to int=
roduce a new form of cast that simply does a compile-time check to verify t=
hat the binary layout is the same. Essentially it could give a compile-erro=
r if the binary layouts of the classes are not equivalent and only compile =
if we are certain that the downcast conversion is safe. It could be as simp=
le as checking that the extended interface does not define any additional s=
tate. If there is no additional state, only member functions (or possibly s=
tatics), any added functionality would live outside of the instance giving =
us no reason to expect any undefined behavior if we were to cast it to the =
newer interface:<br><br><div style=3D"background-color: rgb(250, 250, 250);=
 border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; =
overflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprin=
t"><div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">vector</span><span style=3D"color: #080;" class=3D"styled-by-prettify"=
>&lt;int&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> A </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #0=
66;" class=3D"styled-by-prettify">2</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">,</span><span style=3D"color: #066;" class=3D"styl=
ed-by-prettify">3</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">,</span><span style=3D"color: #066;" class=3D"styled-by-prettify">4<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> B </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> extend_cast</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">extended_vector</span><span style=3D"color: #080;" cla=
ss=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">&amp;&gt;(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">A</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> =C2=A0</span><span style=3D"color: #800;" class=3D"styled-by-pre=
ttify">// OK; same binary layout</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>B</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">accumulate</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #066;" class=3D"styled-by-prettify"=
>2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=A0</span><s=
pan style=3D"color: #800;" class=3D"styled-by-prettify">// should be safe t=
o do this now</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>auto</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> C </span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> extend_cast</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">bad_vector</span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">&lt;int&gt;</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">&amp;&gt;(</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">A</span><span style=3D"colo=
r: #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">// compile error; bad_vector is not binary compatib=
le with std::vector</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>C</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">accum=
ulate</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #066;" class=3D"styled-by-prettify">2</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: #=
800;" class=3D"styled-by-prettify">// not safe, but hopefully will never co=
mpile</span></div></code></div><br><br>This feature would allow us to exten=
d interfaces in C++ style, enabling better encapsulation and readability an=
d encourage the use of classes and inheritance (and as a result better code=
 reuse through access to &#39;protected&#39; members of the base, which we =
would not get through free functions).<br><br>Things might get a bit more c=
omplicated when virtual functions come into play - I&#39;m not entirely cer=
tain if this is still guaranteed to work if virtual methods or overrides ar=
e added, but even if this only applies to non-polymorphic classes I think t=
his might be useful when its pretty common practice to extend external inte=
rfaces, and having to write free functions all the time  is less than ideal=
.. <br><br>[Apologies in advance if something like this has already been pro=
posed or is in this works; I&#39;m not aware of anything as such at the tim=
e of writing.]<br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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/837a9764-71af-46e8-8594-f6b78f4c3c93%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/837a9764-71af-46e8-8594-f6b78f4c3c93=
%40isocpp.org</a>.<br />

------=_Part_4663_978283217.1501030058406--

------=_Part_4662_1401742107.1501030058405--

.