305 lines
28 KiB
HTML
305 lines
28 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
|
|
<meta name="generator" content="Doxygen 1.13.2"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>EnTT: Crash Course: poly</title>
|
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
<script type="text/javascript" src="clipboard.js"></script>
|
|
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="resize.js"></script>
|
|
<script type="text/javascript" src="cookie.js"></script>
|
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
|
<script type="text/javascript" src="search/search.js"></script>
|
|
<link href="doxygen-awesome.css" rel="stylesheet" type="text/css" />
|
|
</head>
|
|
<body>
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
<div id="titlearea">
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tbody>
|
|
<tr id="projectrow">
|
|
<td id="projectalign">
|
|
<div id="projectname">EnTT<span id="projectnumber"> 3.15.0</span>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- end header part -->
|
|
<!-- Generated by Doxygen 1.13.2 -->
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
|
|
var searchBox = new SearchBox("searchBox", "search/",'.html');
|
|
/* @license-end */
|
|
</script>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
|
|
$(function() { codefold.init(0); });
|
|
/* @license-end */
|
|
</script>
|
|
<script type="text/javascript" src="menudata.js"></script>
|
|
<script type="text/javascript" src="menu.js"></script>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
|
|
$(function() {
|
|
initMenu('',true,false,'search.php','Search',false);
|
|
$(function() { init_search(); });
|
|
});
|
|
/* @license-end */
|
|
</script>
|
|
<div id="main-nav"></div>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
|
|
$(function(){ initResizable(false); });
|
|
/* @license-end */
|
|
</script>
|
|
<!-- window showing the filter options -->
|
|
<div id="MSearchSelectWindow"
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
|
</div>
|
|
|
|
<!-- iframe showing the search results (closed by default) -->
|
|
<div id="MSearchResultsWindow">
|
|
<div id="MSearchResults">
|
|
<div class="SRPage">
|
|
<div id="SRIndex">
|
|
<div id="SRResults"></div>
|
|
<div class="SRStatus" id="Loading">Loading...</div>
|
|
<div class="SRStatus" id="Searching">Searching...</div>
|
|
<div class="SRStatus" id="NoMatches">No Matches</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- top -->
|
|
<div id="doc-content">
|
|
<div><div class="header">
|
|
<div class="headertitle"><div class="title">Crash Course: poly</div></div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="textblock"><p><a class="anchor" id="crash-course-poly"></a></p>
|
|
<h1><a class="anchor" id="table-of-contents-10"></a>
|
|
Table of Contents</h1>
|
|
<ul>
|
|
<li><a class="el" href="md_docs_2md_2config.html#introduction">Introduction</a><ul>
|
|
<li><a class="el" href="#other-libraries">Other libraries</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="el" href="#concept-and-implementation">Concept and implementation</a><ul>
|
|
<li><a class="el" href="#deduced-interface">Deduced interface</a></li>
|
|
<li><a class="el" href="#defined-interface">Defined interface</a></li>
|
|
<li><a class="el" href="#fulfill-a-concept">Fulfill a concept</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="el" href="#inheritance">Inheritance</a></li>
|
|
<li><a class="el" href="#static-polymorphism-in-the-wild">Static polymorphism in the wild</a></li>
|
|
<li><a class="el" href="#storage-size-and-alignment-requirement">Storage size and alignment requirement</a></li>
|
|
</ul>
|
|
<h1><a class="anchor" id="introduction-9"></a>
|
|
Introduction</h1>
|
|
<p>Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome to obtain.<br />
|
|
This module aims to make it simple and easy to use.</p>
|
|
<p>The library allows to define <em>concepts</em> as interfaces to fulfill with concrete classes without having to inherit from a common base.<br />
|
|
Among others, this is one of the advantages of static polymorphism in general and of a generic wrapper like that offered by the <code>poly</code> class template in particular.<br />
|
|
The result is an object to pass around as such and not through a reference or a pointer, as it happens when it comes to working with dynamic polymorphism.</p>
|
|
<p>Since the <code>poly</code> class template makes use of <code><a class="el" href="namespaceentt.html#a74619fe0ddf5ff5ea9cf98812a3d70ce" title="Alias declaration for the most common use case.">entt::any</a></code> internally, it also supports most of its feature. For example, the possibility to create aliases to existing and thus unmanaged objects. This allows users to exploit the static polymorphism while maintaining ownership of objects.<br />
|
|
Likewise, the <code>poly</code> class template also benefits from the small buffer optimization offered by the <code><a class="el" href="namespaceentt.html#a74619fe0ddf5ff5ea9cf98812a3d70ce" title="Alias declaration for the most common use case.">entt::any</a></code> class and therefore minimizes the number of allocations, avoiding them altogether where possible.</p>
|
|
<h2><a class="anchor" id="other-libraries"></a>
|
|
Other libraries</h2>
|
|
<p>There are some very interesting libraries regarding static polymorphism.<br />
|
|
The ones that I like more are:</p>
|
|
<ul>
|
|
<li><a href="https://github.com/ldionne/dyno"><code>dyno</code></a>: runtime polymorphism done right.</li>
|
|
<li><a href="https://github.com/facebook/folly/blob/master/folly/docs/Poly.md"><code>Poly</code></a>: a class template that makes it easy to define a type-erasing polymorphic object wrapper.</li>
|
|
</ul>
|
|
<p>The former is admittedly an experimental library, with many interesting ideas. I have some doubts about the usefulness of some features in real world projects, but perhaps my lack of experience comes into play here. In my opinion, its only flaw is the API that I find slightly more cumbersome than other solutions.<br />
|
|
The latter was undoubtedly a source of inspiration for this module. Although I opted for different choices in the implementation of both the final API and some features.</p>
|
|
<p>Either way, the authors are gurus of the C++ community, people I only have to learn from.</p>
|
|
<h1><a class="anchor" id="concept-and-implementation"></a>
|
|
Concept and implementation</h1>
|
|
<p>The first thing to do to create a <em>type-erasing polymorphic object wrapper</em> (to use the terminology introduced by Eric Niebler) is to define a <em>concept</em> that types will have to adhere to.<br />
|
|
For this purpose, the library offers a single class that supports both deduced and fully defined interfaces. Although having interfaces deduced automatically is convenient and allows users to write less code in most cases, it has some limitations. It is therefore useful to be able to get around the deduction by providing a custom definition for the static virtual table.</p>
|
|
<p>Once the interface is defined, a generic implementation is needed to fulfill the concept itself.<br />
|
|
Also in this case, the library allows customizations based on types or families of types, so as to be able to go beyond the generic case where necessary.</p>
|
|
<h2><a class="anchor" id="deduced-interface"></a>
|
|
Deduced interface</h2>
|
|
<p>This is how a concept with a deduced interface is defined:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: Base {</div>
|
|
<div class="line"> <span class="keywordtype">void</span> draw() { this-><span class="keyword">template</span> invoke<0>(*<span class="keyword">this</span>); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
<div class="ttc" id="astructentt_1_1type__list_html"><div class="ttname"><a href="structentt_1_1type__list.html">entt::type_list</a></div><div class="ttdoc">A class to use to push around lists of types, nothing more.</div><div class="ttdef"><b>Definition</b> <a href="core_2type__traits_8hpp_source.html#l00111">type_traits.hpp:111</a></div></div>
|
|
</div><!-- fragment --><p>It is recognizable by the fact that it inherits from an empty type list.<br />
|
|
Functions can also be const, accept any number of parameters and return a type other than <code>void</code>:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: Base {</div>
|
|
<div class="line"> <span class="keywordtype">bool</span> draw(<span class="keywordtype">int</span> pt)<span class="keyword"> const </span>{ <span class="keywordflow">return</span> this-><span class="keyword">template</span> invoke<0>(*<span class="keyword">this</span>, pt); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
</div><!-- fragment --><p>In this case, all parameters are passed to <code>invoke</code> after the reference to <code>this</code> and the return value is whatever the internal call returns.<br />
|
|
As for <code>invoke</code>, this is a name that is injected into the <em>concept</em> through <code>Base</code>, from which one must necessarily inherit. Since it is also a dependent name, the <code>this-> template</code> form is unfortunately necessary due to the rules of the language. However, there also exists an alternative that goes through an external call:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: Base {</div>
|
|
<div class="line"> <span class="keywordtype">void</span> draw()<span class="keyword"> const </span>{ <a class="code hl_function" href="namespaceentt.html#a8b4f2adf317a555138ef5c1cf45b034a">entt::poly_call<0></a>(*<span class="keyword">this</span>); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
<div class="ttc" id="anamespaceentt_html_a8b4f2adf317a555138ef5c1cf45b034a"><div class="ttname"><a href="namespaceentt.html#a8b4f2adf317a555138ef5c1cf45b034a">entt::poly_call</a></div><div class="ttdeci">decltype(auto) poly_call(Poly &&self, Args &&...args)</div><div class="ttdoc">Shortcut for calling poly_base<Type>::invoke.</div><div class="ttdef"><b>Definition</b> <a href="poly_8hpp_source.html#l00173">poly.hpp:173</a></div></div>
|
|
</div><!-- fragment --><p>Once the <em>concept</em> is defined, users must provide a generic implementation of it in order to tell the system how any type can satisfy its requirements. This is done via an alias template within the concept itself.<br />
|
|
The index passed as a template parameter to either <code>invoke</code> or <code>poly_call</code> refers to how this alias is defined.</p>
|
|
<h2><a class="anchor" id="defined-interface"></a>
|
|
Defined interface</h2>
|
|
<p>A fully defined concept is no different to one for which the interface is deduced, with the only difference that the list of types is not empty this time:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><void()> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: Base {</div>
|
|
<div class="line"> <span class="keywordtype">void</span> draw() { <a class="code hl_function" href="namespaceentt.html#a8b4f2adf317a555138ef5c1cf45b034a">entt::poly_call<0></a>(*<span class="keyword">this</span>); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
</div><!-- fragment --><p>Again, parameters and return values other than <code>void</code> are allowed. Also, the function type must be const when the method to bind to it is const:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><bool(int) const> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: Base {</div>
|
|
<div class="line"> <span class="keywordtype">bool</span> draw(<span class="keywordtype">int</span> pt)<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code hl_function" href="namespaceentt.html#a8b4f2adf317a555138ef5c1cf45b034a">entt::poly_call<0></a>(*<span class="keyword">this</span>, pt); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
</div><!-- fragment --><p>Why should a user fully define a concept if the function types are the same as the deduced ones?<br />
|
|
In fact, this is the limitation that can be worked around by manually defining the static virtual table.</p>
|
|
<p>When things are deduced, there is an implicit constraint.<br />
|
|
If the concept exposes a member function called <code>draw</code> with function type <code>void()</code>, a concept is satisfied:</p>
|
|
<ul>
|
|
<li>Either by a class that exposes a member function with the same name and the same signature.</li>
|
|
<li>Or through a lambda that makes use of existing member functions from the interface itself.</li>
|
|
</ul>
|
|
<p>In other words, it is not possible to make use of functions not belonging to the interface, even if they are part of the types that fulfill the concept.<br />
|
|
Similarly, it is not possible to deduce a function in the static virtual table with a function type different from that of the associated member function in the interface itself.</p>
|
|
<p>Explicitly defining a static virtual table suppresses the deduction step and allows maximum flexibility when providing the implementation for a concept.</p>
|
|
<h2><a class="anchor" id="fulfill-a-concept"></a>
|
|
Fulfill a concept</h2>
|
|
<p>The <code>impl</code> alias template of a concept is used to define how it is fulfilled:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><> {</div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Type></div>
|
|
<div class="line"> <span class="keyword">using </span>impl = <a class="code hl_struct" href="structentt_1_1value__list.html">entt::value_list<&Type::draw></a>;</div>
|
|
<div class="line">};</div>
|
|
<div class="ttc" id="astructentt_1_1value__list_html"><div class="ttname"><a href="structentt_1_1value__list.html">entt::value_list</a></div><div class="ttdoc">A class to use to push around lists of constant values, nothing more.</div><div class="ttdef"><b>Definition</b> <a href="core_2type__traits_8hpp_source.html#l00366">type_traits.hpp:366</a></div></div>
|
|
</div><!-- fragment --><p>In this case, it is stated that the <code>draw</code> method of a generic type is enough to satisfy the requirements of the <code>Drawable</code> concept.<br />
|
|
Both member functions and free functions are supported to fulfill concepts:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">template</span><<span class="keyword">typename</span> Type></div>
|
|
<div class="line"><span class="keywordtype">void</span> print(Type &self) { self.print(); }</div>
|
|
<div class="line"> </div>
|
|
<div class="line"><span class="keyword">struct </span>Drawable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><void()> {</div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Type></div>
|
|
<div class="line"> <span class="keyword">using </span>impl = <a class="code hl_struct" href="structentt_1_1value__list.html">entt::value_list<&print<Type></a>>;</div>
|
|
<div class="line">};</div>
|
|
</div><!-- fragment --><p>Likewise, as long as the parameter types and return type support conversions to and from those of the function type referenced in the static virtual table, the actual implementation may differ in its function type since it is erased internally.<br />
|
|
Moreover, the <code>self</code> parameter is not strictly required by the system and can be left out for free functions if not required.</p>
|
|
<p>Refer to the inline documentation for more details.</p>
|
|
<h1><a class="anchor" id="inheritance"></a>
|
|
Inheritance</h1>
|
|
<p><em>Concept inheritance</em> is straightforward due to how poly looks like in <code>EnTT</code>. Therefore, it is quite easy to build hierarchies of concepts if necessary.<br />
|
|
The only constraint is that all concepts in a hierarchy must belong to the same <em>family</em>, that is, they must be either all deduced or all defined.</p>
|
|
<p>For a deduced concept, inheritance is achieved in a few steps:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>DrawableAndErasable: <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><> {</div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Base></div>
|
|
<div class="line"> <span class="keyword">struct </span>type: typename Drawable::type<Base> {</div>
|
|
<div class="line"> <span class="keyword">static</span> <span class="keyword">constexpr</span> <span class="keyword">auto</span> base = Drawable::impl<Drawable::type<entt::poly_inspector>>::size;</div>
|
|
<div class="line"> <span class="keywordtype">void</span> erase() { <a class="code hl_function" href="namespaceentt.html#a8b4f2adf317a555138ef5c1cf45b034a">entt::poly_call<base + 0></a>(*<span class="keyword">this</span>); }</div>
|
|
<div class="line"> };</div>
|
|
<div class="line"> </div>
|
|
<div class="line"> <span class="keyword">template</span><<span class="keyword">typename</span> Type></div>
|
|
<div class="line"> <span class="keyword">using </span>impl = <a class="code hl_typedef" href="namespaceentt.html#a3c9b49e40def274e6187d16435c79602">entt::value_list_cat_t</a><</div>
|
|
<div class="line"> <span class="keyword">typename</span> Drawable::impl<Type>,</div>
|
|
<div class="line"> entt::value_list<&Type::erase></div>
|
|
<div class="line"> >;</div>
|
|
<div class="line">};</div>
|
|
<div class="ttc" id="anamespaceentt_html_a3c9b49e40def274e6187d16435c79602"><div class="ttname"><a href="namespaceentt.html#a3c9b49e40def274e6187d16435c79602">entt::value_list_cat_t</a></div><div class="ttdeci">typename value_list_cat< List... >::type value_list_cat_t</div><div class="ttdoc">Helper type.</div><div class="ttdef"><b>Definition</b> <a href="core_2type__traits_8hpp_source.html#l00517">type_traits.hpp:517</a></div></div>
|
|
</div><!-- fragment --><p>The static virtual table is empty and must remain so.<br />
|
|
On the other hand, <code>type</code> no longer inherits from <code>Base</code>. Instead, it forwards its template parameter to the type exposed by the <em>base class</em>. Internally, the <em>size</em> of the static virtual table of the base class is used as an offset for the local indexes.<br />
|
|
Finally, by means of the <code>value_list_cat_t</code> utility, the implementation consists in appending the new functions to the previous list.</p>
|
|
<p>As for a defined concept instead, the list of types is <em>extended</em> in a similar way to what is shown for the implementation of the above concept.<br />
|
|
To do this, it is useful to declare a function that allows to convert a <em>concept</em> into its underlying <code>type_list</code> object:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">template</span><<span class="keyword">typename</span>... Type></div>
|
|
<div class="line"><a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list</a><Type...> as_type_list(<span class="keyword">const</span> <a class="code hl_struct" href="structentt_1_1type__list.html">entt::type_list<Type...></a> &);</div>
|
|
</div><!-- fragment --><p>The definition is not strictly required, since the function is only used through a <code>decltype</code> as it follows:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">struct </span>DrawableAndErasable: <a class="code hl_typedef" href="namespaceentt.html#a23f80f743d8761c2ff8c6f25c8cafece">entt::type_list_cat_t</a><</div>
|
|
<div class="line"> decltype(as_type_list(std::declval<Drawable>())),</div>
|
|
<div class="line"> entt::type_list<void()>> {</div>
|
|
<div class="line"> <span class="comment">// ...</span></div>
|
|
<div class="line">};</div>
|
|
<div class="ttc" id="anamespaceentt_html_a23f80f743d8761c2ff8c6f25c8cafece"><div class="ttname"><a href="namespaceentt.html#a23f80f743d8761c2ff8c6f25c8cafece">entt::type_list_cat_t</a></div><div class="ttdeci">typename type_list_cat< List... >::type type_list_cat_t</div><div class="ttdoc">Helper type.</div><div class="ttdef"><b>Definition</b> <a href="core_2type__traits_8hpp_source.html#l00252">type_traits.hpp:252</a></div></div>
|
|
</div><!-- fragment --><p>Similar to above, <code>type_list_cat_t</code> is used to concatenate the underlying static virtual table with the new function types.<br />
|
|
Everything else is the same as already shown instead.</p>
|
|
<h1><a class="anchor" id="static-polymorphism-in-the-wild"></a>
|
|
Static polymorphism in the wild</h1>
|
|
<p>Once the <em>concept</em> and implementation are defined, it is possible to use the <code>poly</code> class template to <em>wrap</em> instances that meet the requirements:</p>
|
|
<div class="fragment"><div class="line"><span class="keyword">using </span>drawable = <a class="code hl_typedef" href="namespaceentt.html#ab6d2fe9024bafa328c5f4e4adbc96298">entt::poly<Drawable></a>;</div>
|
|
<div class="line"> </div>
|
|
<div class="line"><span class="keyword">struct </span>circle {</div>
|
|
<div class="line"> <span class="keywordtype">void</span> draw() { <span class="comment">/* ... */</span> }</div>
|
|
<div class="line">};</div>
|
|
<div class="line"> </div>
|
|
<div class="line"><span class="keyword">struct </span>square {</div>
|
|
<div class="line"> <span class="keywordtype">void</span> draw() { <span class="comment">/* ... */</span> }</div>
|
|
<div class="line">};</div>
|
|
<div class="line"> </div>
|
|
<div class="line"><span class="comment">// ...</span></div>
|
|
<div class="line"> </div>
|
|
<div class="line">drawable instance{circle{}};</div>
|
|
<div class="line">instance->draw();</div>
|
|
<div class="line"> </div>
|
|
<div class="line">instance = square{};</div>
|
|
<div class="line">instance->draw();</div>
|
|
<div class="ttc" id="anamespaceentt_html_ab6d2fe9024bafa328c5f4e4adbc96298"><div class="ttname"><a href="namespaceentt.html#ab6d2fe9024bafa328c5f4e4adbc96298">entt::poly</a></div><div class="ttdeci">basic_poly< Concept > poly</div><div class="ttdoc">Alias declaration for the most common use case.</div><div class="ttdef"><b>Definition</b> <a href="poly_2fwd_8hpp_source.html#l00017">fwd.hpp:17</a></div></div>
|
|
</div><!-- fragment --><p>This class offers a wide range of constructors, from the default one (which returns an uninitialized <code>poly</code> object) to the copy and move constructors, as well as the ability to create objects in-place.<br />
|
|
Among others, there is also a constructor that allows users to wrap unmanaged objects in a <code>poly</code> instance (either const or non-const ones):</p>
|
|
<div class="fragment"><div class="line">circle shape;</div>
|
|
<div class="line">drawable instance{std::in_place_type<circle &>, shape};</div>
|
|
</div><!-- fragment --><p>Similarly, it is possible to create non-owning copies of <code>poly</code> from an existing object:</p>
|
|
<div class="fragment"><div class="line">drawable other = instance.as_ref();</div>
|
|
</div><!-- fragment --><p>In both cases, although the interface of the <code>poly</code> object does not change, it does not construct any element or take care of destroying the referenced objects.</p>
|
|
<p>Note also how the underlying concept is accessed via a call to <code>operator-></code> and not directly as <code>instance.draw()</code>.<br />
|
|
This allows users to decouple the API of the wrapper from that of the concept. Therefore, where <code>instance.data()</code> invokes the <code>data</code> member function of the poly object, <code>instance->data()</code> maps directly to the functionality exposed by the underlying concept.</p>
|
|
<h1><a class="anchor" id="storage-size-and-alignment-requirement"></a>
|
|
Storage size and alignment requirement</h1>
|
|
<p>Under the hood, the <code>poly</code> class template makes use of <code><a class="el" href="namespaceentt.html#a74619fe0ddf5ff5ea9cf98812a3d70ce" title="Alias declaration for the most common use case.">entt::any</a></code>. Therefore, it can take advantage of the possibility of defining at compile-time the size of the storage suitable for the small buffer optimization as well as the alignment requirements:</p>
|
|
<div class="fragment"><div class="line"><a class="code hl_class" href="classentt_1_1basic__poly.html">entt::basic_poly</a><Drawable, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>[4]), <span class="keyword">alignof</span>(<span class="keywordtype">double</span>[4])></div>
|
|
<div class="ttc" id="aclassentt_1_1basic__poly_html"><div class="ttname"><a href="classentt_1_1basic__poly.html">entt::basic_poly</a></div><div class="ttdoc">Static polymorphism made simple and within everyone's reach.</div><div class="ttdef"><b>Definition</b> <a href="poly_8hpp_source.html#l00193">poly.hpp:193</a></div></div>
|
|
</div><!-- fragment --><p>The default size is <code>sizeof(double[2])</code>, which seems like a good compromise between a buffer that is too large and one unable to hold anything larger than an integer. The alignment requirement is optional, and by default such that it is the most stringent (the largest) for any object whose size is at most equal to the one provided.<br />
|
|
It is worth noting that providing a size of 0 (which is an accepted value in all respects) will force the system to dynamically allocate the contained objects in all cases. </p>
|
|
</div></div><!-- contents -->
|
|
</div><!-- PageDoc -->
|
|
<!-- start footer part -->
|
|
<hr class="footer"/><address class="footer"><small>
|
|
Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.13.2
|
|
</small></address>
|
|
</div><!-- doc-content -->
|
|
</body>
|
|
</html>
|