| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> |
| <title>Base_From_Member</title> |
| <link rel="stylesheet" href="../../../../doc/src/boostbook.css" type="text/css"> |
| <meta name="generator" content="DocBook XSL Stylesheets V1.78.1"> |
| <link rel="home" href="base_from_member.html" title="Base_From_Member"> |
| </head> |
| <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> |
| <table cellpadding="2" width="100%"><tr> |
| <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../boost.png"></td> |
| <td align="center"><a href="../../../../index.html">Home</a></td> |
| <td align="center"><a href="../../../../libs/libraries.htm">Libraries</a></td> |
| <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> |
| <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> |
| <td align="center"><a href="../../../../more/index.htm">More</a></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"></div> |
| <div class="article"> |
| <div class="titlepage"> |
| <div> |
| <div><h2 class="title"> |
| <a name="base_from_member"></a>Base_From_Member</h2></div> |
| <div><div class="authorgroup"><div class="author"><h3 class="author"> |
| <span class="firstname">Daryle</span> <span class="surname">Walker</span> |
| </h3></div></div></div> |
| <div><p class="copyright">Copyright © 2001, 2003, 2004, 2012 Daryle |
| Walker</p></div> |
| <div><div class="legalnotice"> |
| <a name="base_from_member.legal"></a><p> |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) |
| </p> |
| </div></div> |
| </div> |
| <hr> |
| </div> |
| <div class="toc"> |
| <p><b>Table of Contents</b></p> |
| <dl class="toc"> |
| <dt><span class="section"><a href="base_from_member.html#base_from_member.rationale">Rationale</a></span></dt> |
| <dt><span class="section"><a href="base_from_member.html#base_from_member.synopsis">Synopsis</a></span></dt> |
| <dt><span class="section"><a href="base_from_member.html#base_from_member.usage">Usage</a></span></dt> |
| <dt><span class="section"><a href="base_from_member.html#base_from_member.example">Example</a></span></dt> |
| <dt><span class="section"><a href="base_from_member.html#base_from_member.acknowledgments">Acknowledgments</a></span></dt> |
| </dl> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="base_from_member.rationale"></a><a class="link" href="base_from_member.html#base_from_member.rationale" title="Rationale">Rationale</a> |
| </h2></div></div></div> |
| <p> |
| When developing a class, sometimes a base class needs to be initialized with |
| a member of the current class. As a naïve example: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">/* for std::streambuf */</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">/* for std::ostream */</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdoutbuf</span> |
| <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdostream</span> |
| <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> |
| <span class="special">{</span> |
| <span class="keyword">protected</span><span class="special">:</span> |
| <span class="identifier">fdoutbuf</span> <span class="identifier">buf</span><span class="special">;</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">buf</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">(</span> <span class="special">&</span><span class="identifier">buf</span> <span class="special">)</span> <span class="special">{}</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| This is undefined because C++'s initialization order mandates that the base |
| class is initialized before the member it uses. <a href="http://www.moocat.org" target="_top">R. |
| Samuel Klatchko</a> developed a way around this by using the initialization |
| order in his favor. Base classes are intialized in order of declaration, so |
| moving the desired member to another base class, that is initialized before |
| the desired base class, can ensure proper initialization. |
| </p> |
| <p> |
| A custom base class can be made for this idiom: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">/* for std::streambuf */</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">/* for std::ostream */</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdoutbuf</span> |
| <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">fdostream_pbase</span> |
| <span class="special">{</span> |
| <span class="identifier">fdoutbuf</span> <span class="identifier">sbuffer</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">fdostream_pbase</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">sbuffer</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">)</span> <span class="special">{}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdostream</span> |
| <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">fdostream_pbase</span> |
| <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">fdostream_pbase</span> <span class="identifier">pbase_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">pbase_type</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="special">&</span><span class="identifier">sbuffer</span> <span class="special">)</span> <span class="special">{}</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Other projects can use similar custom base classes. The technique is basic |
| enough to make a template, with a sample template class in this library. The |
| main template parameter is the type of the enclosed member. The template class |
| has several (explicit) constructor member templates, which implicitly type |
| the constructor arguments and pass them to the member. The template class uses |
| implicit copy construction and assignment, cancelling them if the enclosed |
| member is non-copyable. |
| </p> |
| <p> |
| Manually coding a base class may be better if the construction and/or copying |
| needs are too complex for the supplied template class, or if the compiler is |
| not advanced enough to use it. |
| </p> |
| <p> |
| Since base classes are unnamed, a class cannot have multiple (direct) base |
| classes of the same type. The supplied template class has an extra template |
| parameter, an integer, that exists solely to provide type differentiation. |
| This parameter has a default value so a single use of a particular member type |
| does not need to concern itself with the integer. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="base_from_member.synopsis"></a><a class="link" href="base_from_member.html#base_from_member.synopsis" title="Synopsis">Synopsis</a> |
| </h2></div></div></div> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">type_traits</span><span class="special">></span> <span class="comment">/* exposition only */</span> |
| |
| <span class="preprocessor">#ifndef</span> <span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span> |
| <span class="preprocessor">#define</span> <span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span> <span class="number">10</span> |
| <span class="preprocessor">#endif</span> |
| |
| <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">MemberType</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">UniqueID</span> <span class="special">=</span> <span class="number">0</span> <span class="special">></span> |
| <span class="keyword">class</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span> |
| <span class="special">{</span> |
| <span class="keyword">protected</span><span class="special">:</span> |
| <span class="identifier">MemberType</span> <span class="identifier">member</span><span class="special">;</span> |
| |
| <span class="preprocessor">#if</span> <span class="emphasis"><em>C++11 is in use</em></span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="special">...</span><span class="identifier">T</span> <span class="special">></span> |
| <span class="keyword">explicit</span> <span class="keyword">constexpr</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T</span><span class="special">&&</span> <span class="special">...</span><span class="identifier">x</span> <span class="special">)</span> |
| <span class="keyword">noexcept</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_nothrow_constructible</span><span class="special"><</span><span class="identifier">MemberType</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>::</span><span class="identifier">value</span> <span class="special">);</span> |
| <span class="preprocessor">#else</span> |
| <span class="identifier">base_from_member</span><span class="special">();</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span> <span class="special">></span> |
| <span class="keyword">explicit</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span> <span class="special">);</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T2</span> <span class="special">></span> |
| <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span><span class="special">,</span> <span class="identifier">T2</span> <span class="identifier">x2</span> <span class="special">);</span> |
| |
| <span class="comment">//...</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T2</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T3</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T4</span><span class="special">,</span> |
| <span class="keyword">typename</span> <span class="identifier">T5</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T6</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T7</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T8</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T9</span><span class="special">,</span> |
| <span class="keyword">typename</span> <span class="identifier">T10</span> <span class="special">></span> |
| <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span><span class="special">,</span> <span class="identifier">T2</span> <span class="identifier">x2</span><span class="special">,</span> <span class="identifier">T3</span> <span class="identifier">x3</span><span class="special">,</span> <span class="identifier">T4</span> <span class="identifier">x4</span><span class="special">,</span> <span class="identifier">T5</span> <span class="identifier">x5</span><span class="special">,</span> <span class="identifier">T6</span> <span class="identifier">x6</span><span class="special">,</span> <span class="identifier">T7</span> <span class="identifier">x7</span><span class="special">,</span> |
| <span class="identifier">T8</span> <span class="identifier">x8</span><span class="special">,</span> <span class="identifier">T9</span> <span class="identifier">x9</span><span class="special">,</span> <span class="identifier">T10</span> <span class="identifier">x10</span> <span class="special">);</span> |
| <span class="preprocessor">#endif</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">MemberType</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">UniqueID</span> <span class="special">></span> |
| <span class="keyword">class</span> <span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">MemberType</span><span class="special">&,</span> <span class="identifier">UniqueID</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">protected</span><span class="special">:</span> |
| <span class="identifier">MemberType</span><span class="special">&</span> <span class="identifier">member</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="keyword">constexpr</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">MemberType</span><span class="special">&</span> <span class="identifier">x</span> <span class="special">)</span> |
| <span class="keyword">noexcept</span><span class="special">;</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The class template has a first template parameter <code class="computeroutput"><span class="identifier">MemberType</span></code> |
| representing the type of the based-member. It has a last template parameter |
| <code class="computeroutput"><span class="identifier">UniqueID</span></code>, that is an <code class="computeroutput"><span class="keyword">int</span></code>, to differentiate between multiple base |
| classes that use the same based-member type. The last template parameter has |
| a default value of zero if it is omitted. The class template has a protected |
| data member called <code class="computeroutput"><span class="identifier">member</span></code> that |
| the derived class can use for later base classes (or itself). |
| </p> |
| <p> |
| If the appropriate features of C++11 are present, there will be a single constructor |
| template. It implements <span class="emphasis"><em>perfect forwarding</em></span> to the best |
| constructor call of <code class="computeroutput"><span class="identifier">member</span></code> |
| (if any). The constructor template is marked both <code class="computeroutput"><span class="keyword">constexpr</span></code> |
| and <code class="computeroutput"><span class="keyword">explicit</span></code>. The former will |
| be ignored if the corresponding inner constructor call (of <code class="computeroutput"><span class="identifier">member</span></code>) |
| does not have the marker. The latter binds the other way; always taking effect, |
| even when the inner constructor call does not have the marker. The constructor |
| template propagates the <code class="computeroutput"><span class="keyword">noexcept</span></code> |
| status of the inner constructor call. (The constructor template has a trailing |
| parameter with a default value that disables the template when its signature |
| is too close to the signatures of the automatically-defined non-template copy- |
| and/or move-constructors of <code class="computeroutput"><span class="identifier">base_from_member</span></code>.) |
| </p> |
| <p> |
| On earlier-standard compilers, there is a default constructor and several constructor |
| member templates. These constructor templates can take as many arguments (currently |
| up to ten) as possible and pass them to a constructor of the data member. |
| </p> |
| <p> |
| A specialization for member references offers a single constructor taking a |
| <code class="computeroutput"><span class="identifier">MemberType</span><span class="special">&</span></code>, |
| which is the only way to initialize a reference. |
| </p> |
| <p> |
| Since C++ does not allow any way to explicitly state the template parameters |
| of a templated constructor, make sure that the arguments are already close |
| as possible to the actual type used in the data member's desired constructor. |
| Explicit conversions may be necessary. |
| </p> |
| <p> |
| The <code class="computeroutput"><span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span></code> |
| macro constant specifies the maximum argument length for the constructor templates. |
| The constant may be overridden if more (or less) argument configurations are |
| needed. The constant may be read for code that is expandable like the class |
| template and needs to maintain the same maximum size. (Example code would be |
| a class that uses this class template as a base class for a member with a flexible |
| set of constructors.) This constant is ignored when C++11 features are present. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="base_from_member.usage"></a><a class="link" href="base_from_member.html#base_from_member.usage" title="Usage">Usage</a> |
| </h2></div></div></div> |
| <p> |
| With the starting example, the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code> |
| sub-object needs to be encapsulated in a base class that is inheirited before |
| <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>. |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">base_from_member</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">// for std::streambuf</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">// for std::ostream</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdoutbuf</span> |
| <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">fdostream</span> |
| <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">fdoutbuf</span><span class="special">></span> |
| <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> |
| <span class="special">{</span> |
| <span class="comment">// Helper typedef's</span> |
| <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">fdoutbuf</span><span class="special">></span> <span class="identifier">pbase_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">pbase_type</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="special">&</span><span class="identifier">member</span> <span class="special">){}</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The base-from-member idiom is an implementation detail, so it should not be |
| visible to the clients (or any derived classes) of <code class="computeroutput"><span class="identifier">fdostream</span></code>. |
| Due to the initialization order, the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code> |
| sub-object will get initialized before the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code> |
| sub-object does, making the former sub-object safe to use in the latter sub-object's |
| construction. Since the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code> |
| sub-object of the final type is the only sub-object with the name <code class="computeroutput"><span class="identifier">member</span></code> that name can be used unqualified |
| within the final class. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="base_from_member.example"></a><a class="link" href="base_from_member.html#base_from_member.example" title="Example">Example</a> |
| </h2></div></div></div> |
| <p> |
| The base-from-member class templates should commonly involve only one base-from-member |
| sub-object, usually for attaching a stream-buffer to an I/O stream. The next |
| example demonstrates how to use multiple base-from-member sub-objects and the |
| resulting qualification issues. |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">base_from_member</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstddef</span><span class="special">></span> <span class="comment">/* for NULL */</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">an_int</span> |
| <span class="special">{</span> |
| <span class="keyword">int</span> <span class="identifier">y</span><span class="special">;</span> |
| |
| <span class="identifier">an_int</span><span class="special">(</span> <span class="keyword">float</span> <span class="identifier">yf</span> <span class="special">);</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">switcher</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="identifier">switcher</span><span class="special">();</span> |
| <span class="identifier">switcher</span><span class="special">(</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">int</span> <span class="special">*</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">flow_regulator</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="identifier">flow_regulator</span><span class="special">(</span> <span class="identifier">switcher</span> <span class="special">&,</span> <span class="identifier">switcher</span> <span class="special">&</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">unsigned</span> <span class="identifier">Size</span> <span class="special">></span> |
| <span class="keyword">class</span> <span class="identifier">fan</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">explicit</span> <span class="identifier">fan</span><span class="special">(</span> <span class="identifier">switcher</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">class</span> <span class="identifier">system</span> |
| <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">an_int</span><span class="special">></span> |
| <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">></span> |
| <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> |
| <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> |
| <span class="special">,</span> <span class="keyword">protected</span> <span class="identifier">flow_regulator</span> |
| <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">fan</span><span class="special"><</span><span class="number">6</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// Helper typedef's</span> |
| <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">an_int</span><span class="special">></span> <span class="identifier">pbase0_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">></span> <span class="identifier">pbase1_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">pbase2_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">pbase3_type</span><span class="special">;</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">flow_regulator</span> <span class="identifier">base1_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">fan</span><span class="special"><</span><span class="number">6</span><span class="special">></span> <span class="identifier">base2_type</span><span class="special">;</span> |
| |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="identifier">system</span><span class="special">(</span> <span class="keyword">double</span> <span class="identifier">x</span> <span class="special">);</span> |
| <span class="comment">//...</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">system</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span> <span class="keyword">double</span> <span class="identifier">x</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">pbase0_type</span><span class="special">(</span> <span class="number">0.2</span> <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">pbase1_type</span><span class="special">()</span> |
| <span class="special">,</span> <span class="identifier">pbase2_type</span><span class="special">(</span> <span class="special">-</span><span class="number">16</span><span class="special">,</span> <span class="special">&</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">pbase0_type</span><span class="special">::</span><span class="identifier">member</span><span class="special">.</span><span class="identifier">y</span> <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">pbase3_type</span><span class="special">(</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">int</span> <span class="special">*>(</span><span class="identifier">NULL</span><span class="special">)</span> <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">base1_type</span><span class="special">(</span> <span class="identifier">pbase3_type</span><span class="special">::</span><span class="identifier">member</span><span class="special">,</span> <span class="identifier">pbase1_type</span><span class="special">::</span><span class="identifier">member</span> <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">base2_type</span><span class="special">(</span> <span class="identifier">pbase2_type</span><span class="special">::</span><span class="identifier">member</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">//...</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| The final class has multiple sub-objects with the name <code class="computeroutput"><span class="identifier">member</span></code>, |
| so any use of that name needs qualification by a name of the appropriate base |
| type. (Using <code class="computeroutput"><span class="keyword">typedef</span></code>s ease mentioning |
| the base types.) However, the fix introduces a new problem when a pointer is |
| needed. Using the address operator with a sub-object qualified with its class's |
| name results in a pointer-to-member (here, having a type of <code class="computeroutput"><span class="identifier">an_int</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span> |
| <span class="identifier">an_int</span><span class="special">,</span> |
| <span class="number">0</span><span class="special">></span> <span class="special">::</span> <span class="special">*</span></code>) instead |
| of a pointer to the member (having a type of <code class="computeroutput"><span class="identifier">an_int</span> |
| <span class="special">*</span></code>). The new problem is fixed by qualifying |
| the sub-object with <code class="computeroutput"><span class="keyword">this</span><span class="special">-></span></code> |
| and is needed just for pointers, and not for references or values. |
| </p> |
| <p> |
| There are some argument conversions in the initialization. The constructor |
| argument for <code class="computeroutput"><span class="identifier">pbase0_type</span></code> is |
| converted from <code class="computeroutput"><span class="keyword">double</span></code> to <code class="computeroutput"><span class="keyword">float</span></code>. The first constructor argument for <code class="computeroutput"><span class="identifier">pbase2_type</span></code> is converted from <code class="computeroutput"><span class="keyword">int</span></code> to <code class="computeroutput"><span class="keyword">double</span></code>. |
| The second constructor argument for <code class="computeroutput"><span class="identifier">pbase3_type</span></code> |
| is a special case of necessary conversion; all forms of the null-pointer literal |
| in C++ (except <code class="computeroutput"><span class="keyword">nullptr</span></code> from C++11) |
| also look like compile-time integral expressions, so C++ always interprets |
| such code as an integer when it has overloads that can take either an integer |
| or a pointer. The last conversion is necessary for the compiler to call a constructor |
| form with the exact pointer type used in <code class="computeroutput"><span class="identifier">switcher</span></code>'s |
| constructor. (If C++11's <code class="computeroutput"><span class="keyword">nullptr</span></code> |
| is used, it still needs a conversion if multiple pointer types can be accepted |
| in a constructor call but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">nullptr_t</span></code> |
| cannot.) |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="base_from_member.acknowledgments"></a><a class="link" href="base_from_member.html#base_from_member.acknowledgments" title="Acknowledgments">Acknowledgments</a> |
| </h2></div></div></div> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <a href="http://www.boost.org/people/ed_brey.htm" target="_top">Ed Brey</a> suggested |
| some interface changes. |
| </li> |
| <li class="listitem"> |
| <a href="http://www.moocat.org" target="_top">R. Samuel Klatchko</a> (<a href="mailto:rsk%40moocat.org" target="_top">rsk@moocat.org</a>, |
| <a href="mailto:rsk%40brightmail.com" target="_top">rsk@brightmail.com</a>) invented |
| the idiom of how to use a class member for initializing a base class. |
| </li> |
| <li class="listitem"> |
| <a href="http://www.boost.org/people/dietmar_kuehl.htm" target="_top">Dietmar Kuehl</a> |
| popularized the base-from-member idiom in his <a href="http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/" target="_top">IOStream |
| example classes</a>. |
| </li> |
| <li class="listitem"> |
| Jonathan Turkanis supplied an implementation of generating the constructor |
| templates that can be controlled and automated with macros. The implementation |
| uses the <a href="../../../preprocessor/index.html" target="_top">Preprocessor library</a>. |
| </li> |
| <li class="listitem"> |
| <a href="http://www.boost.org/people/daryle_walker.html%22%3eDaryle" target="_top">Walker</a> |
| started the library. Contributed the test file <a href="../../base_from_member_test.cpp" target="_top">base_from_member_test.cpp</a>. |
| </li> |
| </ul></div> |
| </div> |
| </div> |
| <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> |
| <td align="left"><p><small>Last revised: April 07, 2015 at 22:46:48 GMT</small></p></td> |
| <td align="right"><div class="copyright-footer"></div></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"></div> |
| </body> |
| </html> |