Topic: empty_base and optional_base


Author: rhalbersma@gmail.com
Date: Tue, 4 Aug 2015 00:57:33 -0700 (PDT)
Raw View
------=_Part_2352_1157596572.1438675053713
Content-Type: multipart/alternative;
 boundary="----=_Part_2353_233741638.1438675053713"

------=_Part_2353_233741638.1438675053713
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



In generic code, I sometimes want to conditionally add a data member to a c=
lass template. Writing separate template specializations scales as 2^N for =
N conditional data members. Absent a static_if feature, I have found class =
templates empty_base<T> and optional_base<T> useful:


namespace xstd {

namespace block_adl {template<class>struct empty_base{        empty_base() =
=3D default;        template<class... Args>        constexpr empty_base(Arg=
s&&...) {}};template<bool Condition, class T>using optional_base =3D std::c=
onditional_t<Condition, T, empty_base<T>>;}       // namespace block_adl// =
deriving from empty_base or optional_base will not make xstd an associated =
namespace// this prevents ADL from finding overloads for e.g. begin/end/swa=
p from namespace xstdusing block_adl::empty_base;using block_adl::optional_=
base;}       // namespace xstd


Exploiting the empty base optimization then allows users to write class tem=
plates that have optional data members (conditional on template variable tr=
aits Traits1_v and Traits2_v)


template<class T>
class Test
:
    public Base0, // unconditional base class
    public xstd::optional_base<Trait1_v<T>, Base1>,
    public xstd::optional_base<Trait2_v<T>, Base2>
{
    using B1 =3D xstd::optional_base<Trait1_v<T>, Base1>;
    using B2 =3D xstd::optional_base<Trait2_v<T>, Base2>;
public:

    Test() =3D default;

   =20
    Test(Arg0 const& a0, Arg1 const& a1, Arg2 const& a2)
    :
        Base0(a0),
        B1(a1),
        B2(a2)
    {}   =20
};


Note that the optional_base variadic constructor allows linear scaling of=
=20
constructor delegation in the user-defined class template Test. One minor=
=20
wart is that this constructor does require passing all parameters (but=20
otherwise, 2^N different constructors have to be written). But if any of=20
the traits variables evaluates to false, the corresponding parameter and=20
call to the base constructor will be optimized away. And because=20
optional_base also has a trivial default constructor, POD-ness of=20
user-defined classes is preserved by inheriting from it.=20

Obviously, over-use of inheritance has to be avoided, but the above design=
=20
does avoid quite a lot of code duplication. Oh, and I haven't tested this=
=20
with virtual functions, virtual base classes and what-not. I just use this=
=20
for assembling value-semantic classes out of conditional building blocks.

In any case, now that <type_traits> will get new metaprogramming features=
=20
as nonesuch and void_t, I wonder whether there is any demand for something=
=20
along the lines of empty_base and optional_base.


  =20

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_2353_233741638.1438675053713
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><pre style=3D"font-size: 12px; line-height: 1.4;"><font fa=
ce=3D"arial, sans-serif">In generic code, I sometimes want to conditionally=
 add a data member to a class template. Writing separate template specializ=
ations scales as 2^N for N conditional data members. Absent a </font><font =
color=3D"#0000ff" face=3D"courier new, monospace">static_if</font><font fac=
e=3D"arial, sans-serif"> feature, I have found class templates</font> <font=
 face=3D"courier new, monospace" color=3D"#0000ff">empty_base&lt;T&gt;</fon=
t> <font face=3D"arial, sans-serif">and</font> <font color=3D"#0000ff" face=
=3D"courier new, monospace">optional_base&lt;T&gt; </font><font face=3D"ari=
al, sans-serif"><font color=3D"#000000">useful</font>:</font></pre><pre sty=
le=3D"font-size: 12px; line-height: 1.4;"><span class=3D"k" style=3D"font-w=
eight: bold;"><font face=3D"courier new, monospace" color=3D"#0000ff"><br><=
/font></span></pre><pre style=3D"font-size: 12px; line-height: 1.4;"><span =
class=3D"k" style=3D"font-weight: bold;"><font face=3D"courier new, monospa=
ce" color=3D"#0000ff">namespace xstd {</font></span></pre><pre style=3D"fon=
t-size: 12px; line-height: 1.4;"><font face=3D"courier new, monospace" colo=
r=3D"#0000ff"><span class=3D"k" style=3D"font-weight: bold;">namespace</spa=
n> <span class=3D"n">block_adl</span> <span class=3D"p">{</span>
<a name=3D"type_traits.hpp-101"></a>
<a name=3D"type_traits.hpp-102"></a><span class=3D"k" style=3D"font-weight:=
 bold;">template</span><span class=3D"o" style=3D"font-weight: bold;">&lt;<=
/span><span class=3D"n">class</span><span class=3D"o" style=3D"font-weight:=
 bold;">&gt;</span>
<a name=3D"type_traits.hpp-103"></a><span class=3D"k" style=3D"font-weight:=
 bold;">struct</span> <span class=3D"n">empty_base</span>
<a name=3D"type_traits.hpp-104"></a><span class=3D"p">{</span>
<a name=3D"type_traits.hpp-105"></a>        <span class=3D"n">empty_base</s=
pan><span class=3D"p">()</span> <span class=3D"o" style=3D"font-weight: bol=
d;">=3D</span> <span class=3D"k" style=3D"font-weight: bold;">default</span=
><span class=3D"p">;</span>
<a name=3D"type_traits.hpp-106"></a>
<a name=3D"type_traits.hpp-107"></a>        <span class=3D"k" style=3D"font=
-weight: bold;">template</span><span class=3D"o" style=3D"font-weight: bold=
;">&lt;</span><span class=3D"n">class</span><span class=3D"p">...</span> <s=
pan class=3D"n">Args</span><span class=3D"o" style=3D"font-weight: bold;">&=
gt;</span>
<a name=3D"type_traits.hpp-108"></a>        <span class=3D"k" style=3D"font=
-weight: bold;">constexpr</span> <span class=3D"n">empty_base</span><span c=
lass=3D"p">(</span><span class=3D"n">Args</span><span class=3D"o" style=3D"=
font-weight: bold;">&amp;&amp;</span><span class=3D"p">...)</span> <span cl=
ass=3D"p">{}</span>
<a name=3D"type_traits.hpp-109"></a><span class=3D"p">};</span>
<a name=3D"type_traits.hpp-110"></a>
<a name=3D"type_traits.hpp-111"></a><span class=3D"k" style=3D"font-weight:=
 bold;">template</span><span class=3D"o" style=3D"font-weight: bold;">&lt;<=
/span><span class=3D"kt" style=3D"font-weight: bold;">bool</span> <span cla=
ss=3D"n">Condition</span><span class=3D"p">,</span> <span class=3D"k" style=
=3D"font-weight: bold;">class</span> <span class=3D"nc" style=3D"font-weigh=
t: bold;">T</span><span class=3D"o" style=3D"font-weight: bold;">&gt;</span=
>
<a name=3D"type_traits.hpp-112"></a><span class=3D"k" style=3D"font-weight:=
 bold;">using</span> <span class=3D"n">optional_base</span> <span class=3D"=
o" style=3D"font-weight: bold;">=3D</span> <span class=3D"n">std</span><spa=
n class=3D"o" style=3D"font-weight: bold;">::</span><span class=3D"kt" styl=
e=3D"font-weight: bold;">conditional_t</span><span class=3D"o" style=3D"fon=
t-weight: bold;">&lt;</span><span class=3D"n">Condition</span><span class=
=3D"p">,</span> <span class=3D"n">T</span><span class=3D"p">,</span> <span =
class=3D"n">empty_base</span><span class=3D"o" style=3D"font-weight: bold;"=
>&lt;</span><span class=3D"n">T</span><span class=3D"o" style=3D"font-weigh=
t: bold;">&gt;&gt;</span><span class=3D"p">;</span>
<a name=3D"type_traits.hpp-113"></a>
<a name=3D"type_traits.hpp-114"></a><span class=3D"p">}</span>       <span =
class=3D"c1" style=3D"font-style: italic;">// namespace block_adl</span>
<a name=3D"type_traits.hpp-115"></a>
<a name=3D"type_traits.hpp-116"></a><span class=3D"c1" style=3D"font-style:=
 italic;">// deriving from empty_base or optional_base will not make xstd a=
n associated namespace</span>
<a name=3D"type_traits.hpp-117"></a><span class=3D"c1" style=3D"font-style:=
 italic;">// this prevents ADL from finding overloads for e.g. begin/end/sw=
ap from namespace xstd</span>
<a name=3D"type_traits.hpp-118"></a><span class=3D"k" style=3D"font-weight:=
 bold;">using</span> <span class=3D"n">block_adl</span><span class=3D"o" st=
yle=3D"font-weight: bold;">::</span><span class=3D"n">empty_base</span><spa=
n class=3D"p">;</span>
<a name=3D"type_traits.hpp-119"></a><span class=3D"k" style=3D"font-weight:=
 bold;">using</span> <span class=3D"n">block_adl</span><span class=3D"o" st=
yle=3D"font-weight: bold;">::</span><span class=3D"n">optional_base</span><=
span class=3D"p">;</span>
<a name=3D"type_traits.hpp-120"></a>
<a name=3D"type_traits.hpp-121"></a><span class=3D"p">}</span>       <span =
class=3D"c1" style=3D"font-style: italic;">// namespace xstd</span></font><=
/pre><pre style=3D"font-size: 12px; line-height: 1.4;"><font face=3D"courie=
r new, monospace" color=3D"#0000ff"><span class=3D"c1" style=3D"font-style:=
 italic;"><br></span></font></pre><pre style=3D"font-size: 12px; line-heigh=
t: 1.4;"><font color=3D"#000000" face=3D"arial, sans-serif">Exploiting the =
empty base optimization then allows users to write class templates that hav=
e optional data members (conditional on template variable traits Traits1_v =
and Traits2_v)</font></pre><pre style=3D"font-size: 12px; line-height: 1.4;=
"><font face=3D"courier new, monospace" color=3D"#000000"><br></font></pre>=
<pre><font face=3D"courier new, monospace" color=3D"#0000ff"><span style=3D=
"font-size: 12px; line-height: 16.7999992370605px;">template&lt;class T&gt;
class Test
:
    public Base0, // unconditional base class
    public xstd::optional_base&lt;Trait1_v&lt;T&gt;, Base1&gt;,
    public xstd::optional_base&lt;Trait2_v&lt;T&gt;, Base2&gt;
{
    using B1 =3D xstd::optional_base&lt;Trait1_v&lt;T&gt;, Base1&gt;;
    using B2 =3D xstd::optional_base&lt;Trait2_v&lt;T&gt;, Base2&gt;;
public:</span></font></pre><pre><font face=3D"courier new, monospace" color=
=3D"#0000ff"><span style=3D"font-size: 12px; line-height: 16.7999992370605p=
x;">    Test() =3D default;</span></font></pre><pre><font face=3D"courier n=
ew, monospace" color=3D"#0000ff"><span style=3D"font-size: 12px; line-heigh=
t: 16.7999992370605px;">   =20
    Test(Arg0 const&amp; a0, Arg1 const&amp; a1, Arg2 const&amp; a2)
    :
        Base0(a0),
        B1(a1),
        B2(a2)
    {}   =20
};</span><span style=3D"font-size: 12px; line-height: 1.4;">
</span></font></pre><div><font face=3D"courier new, monospace" color=3D"#00=
0000"><br></font></div><div><font color=3D"#000000" face=3D"arial, sans-ser=
if">Note that the </font><font face=3D"courier new, monospace" color=3D"#00=
00ff">optional_base</font><font color=3D"#000000" face=3D"arial, sans-serif=
"> variadic constructor allows linear scaling of constructor delegation in =
the user-defined class template </font><font color=3D"#0000ff" face=3D"cour=
ier new, monospace">Test</font><font color=3D"#000000" face=3D"arial, sans-=
serif">. One minor wart is that this constructor does require passing all p=
arameters (but otherwise, 2^N different constructors have to be written). B=
ut i</font><span style=3D"color: rgb(0, 0, 0); font-family: arial, sans-ser=
if;">f any of the traits variables evaluates to false, the corresponding pa=
rameter and call to the base constructor will be optimized away.</span><spa=
n style=3D"color: rgb(0, 0, 0); font-family: arial, sans-serif;">=C2=A0</sp=
an><font color=3D"#000000" face=3D"arial, sans-serif">And because </font><f=
ont face=3D"courier new, monospace" color=3D"#0000ff">optional_base</font><=
font color=3D"#000000" face=3D"arial, sans-serif"> also has a trivial defau=
lt constructor, POD-ness of user-defined classes is preserved by inheriting=
 from it.=C2=A0</font></div><div><font color=3D"#000000" face=3D"arial, san=
s-serif"><br></font></div><div><font color=3D"#000000" face=3D"arial, sans-=
serif">Obviously, over-use of inheritance has to be avoided, but the above =
design does avoid quite a lot of code duplication. Oh, and I haven&#39;t te=
sted this with virtual functions, virtual base classes and what-not. I just=
 use this for assembling value-semantic classes out of conditional building=
 blocks.</font></div><div><font color=3D"#000000" face=3D"arial, sans-serif=
"><br></font></div><div><font color=3D"#000000" face=3D"arial, sans-serif">=
In any case, now that </font><font face=3D"courier new, monospace" color=3D=
"#0000ff">&lt;type_traits&gt;</font><font color=3D"#000000" face=3D"arial, =
sans-serif"> will get new metaprogramming features as </font><font face=3D"=
arial, sans-serif" color=3D"#0000ff">nonesuch</font><font color=3D"#000000"=
 face=3D"arial, sans-serif"> and </font><font face=3D"arial, sans-serif" co=
lor=3D"#0000ff">void_t</font><font color=3D"#000000" face=3D"arial, sans-se=
rif">, I wonder whether there is any demand for something along the lines o=
f=C2=A0</font><font face=3D"arial, sans-serif" color=3D"#0000ff">empty_base=
</font><font color=3D"#000000" face=3D"arial, sans-serif"> and </font><font=
 face=3D"arial, sans-serif" color=3D"#0000ff">optional_base</font><font col=
or=3D"#000000" face=3D"arial, sans-serif">.</font></div><pre style=3D"font-=
size: 12px; line-height: 1.4;"><font face=3D"courier new, monospace" color=
=3D"#000000"><br></font></pre><pre style=3D"font-size: 12px; line-height: 1=
..4;"><span style=3D"color: rgb(0, 0, 0); font-family: &#39;courier new&#39;=
, monospace; line-height: 1.4;">   </span><br></pre></div>

<p></p>

-- <br />
<br />
--- <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 />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_2353_233741638.1438675053713--
------=_Part_2352_1157596572.1438675053713--

.