mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-26 06:42:23 +00:00
6257 lines
221 KiB
HTML
6257 lines
221 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="Asciidoctor 2.0.20">
|
||
<meta name="author" content="Jean-Louis Leroy">
|
||
<title>Boost.OpenMethod</title>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
|
||
<style>
|
||
/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
|
||
/* Uncomment the following line when using as a custom stylesheet */
|
||
/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
|
||
html{font-family:sans-serif;-webkit-text-size-adjust:100%}
|
||
a{background:none}
|
||
a:focus{outline:thin dotted}
|
||
a:active,a:hover{outline:0}
|
||
h1{font-size:2em;margin:.67em 0}
|
||
b,strong{font-weight:bold}
|
||
abbr{font-size:.9em}
|
||
abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
|
||
dfn{font-style:italic}
|
||
hr{height:0}
|
||
mark{background:#ff0;color:#000}
|
||
code,kbd,pre,samp{font-family:monospace;font-size:1em}
|
||
pre{white-space:pre-wrap}
|
||
q{quotes:"\201C" "\201D" "\2018" "\2019"}
|
||
small{font-size:80%}
|
||
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||
sup{top:-.5em}
|
||
sub{bottom:-.25em}
|
||
img{border:0}
|
||
svg:not(:root){overflow:hidden}
|
||
figure{margin:0}
|
||
audio,video{display:inline-block}
|
||
audio:not([controls]){display:none;height:0}
|
||
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
|
||
legend{border:0;padding:0}
|
||
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
|
||
button,input{line-height:normal}
|
||
button,select{text-transform:none}
|
||
button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
|
||
button[disabled],html input[disabled]{cursor:default}
|
||
input[type=checkbox],input[type=radio]{padding:0}
|
||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
|
||
textarea{overflow:auto;vertical-align:top}
|
||
table{border-collapse:collapse;border-spacing:0}
|
||
*,::before,::after{box-sizing:border-box}
|
||
html,body{font-size:100%}
|
||
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
|
||
a:hover{cursor:pointer}
|
||
img,object,embed{max-width:100%;height:auto}
|
||
object,embed{height:100%}
|
||
img{-ms-interpolation-mode:bicubic}
|
||
.left{float:left!important}
|
||
.right{float:right!important}
|
||
.text-left{text-align:left!important}
|
||
.text-right{text-align:right!important}
|
||
.text-center{text-align:center!important}
|
||
.text-justify{text-align:justify!important}
|
||
.hide{display:none}
|
||
img,object,svg{display:inline-block;vertical-align:middle}
|
||
textarea{height:auto;min-height:50px}
|
||
select{width:100%}
|
||
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
|
||
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
|
||
a{color:#2156a5;text-decoration:underline;line-height:inherit}
|
||
a:hover,a:focus{color:#1d4b8f}
|
||
a img{border:0}
|
||
p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
|
||
p aside{font-size:.875em;line-height:1.35;font-style:italic}
|
||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
|
||
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
|
||
h1{font-size:2.125em}
|
||
h2{font-size:1.6875em}
|
||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
|
||
h4,h5{font-size:1.125em}
|
||
h6{font-size:1em}
|
||
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
|
||
em,i{font-style:italic;line-height:inherit}
|
||
strong,b{font-weight:bold;line-height:inherit}
|
||
small{font-size:60%;line-height:inherit}
|
||
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
|
||
ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
|
||
ul,ol{margin-left:1.5em}
|
||
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
|
||
ul.circle{list-style-type:circle}
|
||
ul.disc{list-style-type:disc}
|
||
ul.square{list-style-type:square}
|
||
ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
|
||
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
|
||
dl dt{margin-bottom:.3125em;font-weight:bold}
|
||
dl dd{margin-bottom:1.25em}
|
||
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
|
||
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
|
||
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
|
||
h1{font-size:2.75em}
|
||
h2{font-size:2.3125em}
|
||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
|
||
h4{font-size:1.4375em}}
|
||
table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
|
||
table thead,table tfoot{background:#f7f8f7}
|
||
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
|
||
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
|
||
table tr.even,table tr.alt{background:#f8f8f7}
|
||
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
|
||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
|
||
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
|
||
.center{margin-left:auto;margin-right:auto}
|
||
.stretch{width:100%}
|
||
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
|
||
.clearfix::after,.float-group::after{clear:both}
|
||
:not(pre).nobreak{word-wrap:normal}
|
||
:not(pre).nowrap{white-space:nowrap}
|
||
:not(pre).pre-wrap{white-space:pre-wrap}
|
||
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
|
||
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
|
||
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
|
||
pre>code{display:block}
|
||
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
|
||
em em{font-style:normal}
|
||
strong strong{font-weight:400}
|
||
.keyseq{color:rgba(51,51,51,.8)}
|
||
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
|
||
.keyseq kbd:first-child{margin-left:0}
|
||
.keyseq kbd:last-child{margin-right:0}
|
||
.menuseq,.menuref{color:#000}
|
||
.menuseq b:not(.caret),.menuref{font-weight:inherit}
|
||
.menuseq{word-spacing:-.02em}
|
||
.menuseq b.caret{font-size:1.25em;line-height:.8}
|
||
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
|
||
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
|
||
b.button::before{content:"[";padding:0 3px 0 2px}
|
||
b.button::after{content:"]";padding:0 2px 0 3px}
|
||
p a>code:hover{color:rgba(0,0,0,.9)}
|
||
#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
|
||
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
|
||
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
|
||
#content{margin-top:1.25em}
|
||
#content::before{content:none}
|
||
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
|
||
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
|
||
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
|
||
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
|
||
#header .details span:first-child{margin-left:-.125em}
|
||
#header .details span.email a{color:rgba(0,0,0,.85)}
|
||
#header .details br{display:none}
|
||
#header .details br+span::before{content:"\00a0\2013\00a0"}
|
||
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
|
||
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
|
||
#header #revnumber{text-transform:capitalize}
|
||
#header #revnumber::after{content:"\00a0"}
|
||
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
|
||
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
|
||
#toc>ul{margin-left:.125em}
|
||
#toc ul.sectlevel0>li>a{font-style:italic}
|
||
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
|
||
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
|
||
#toc li{line-height:1.3334;margin-top:.3334em}
|
||
#toc a{text-decoration:none}
|
||
#toc a:active{text-decoration:underline}
|
||
#toctitle{color:#7a2518;font-size:1.2em}
|
||
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
|
||
body.toc2{padding-left:15em;padding-right:0}
|
||
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
|
||
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
|
||
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
|
||
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
|
||
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
|
||
body.toc2.toc-right{padding-left:0;padding-right:15em}
|
||
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
|
||
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
|
||
#toc.toc2{width:20em}
|
||
#toc.toc2 #toctitle{font-size:1.375em}
|
||
#toc.toc2>ul{font-size:.95em}
|
||
#toc.toc2 ul ul{padding-left:1.25em}
|
||
body.toc2.toc-right{padding-left:0;padding-right:20em}}
|
||
#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
|
||
#content #toc>:first-child{margin-top:0}
|
||
#content #toc>:last-child{margin-bottom:0}
|
||
#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
|
||
#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
|
||
#content{margin-bottom:.625em}
|
||
.sect1{padding-bottom:.625em}
|
||
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
|
||
.sect1{padding-bottom:1.25em}}
|
||
.sect1:last-child{padding-bottom:0}
|
||
.sect1+.sect1{border-top:1px solid #e7e7e9}
|
||
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
|
||
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
|
||
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
|
||
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
|
||
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
|
||
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
|
||
details{margin-left:1.25rem}
|
||
details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
|
||
details>summary::-webkit-details-marker{display:none}
|
||
details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
|
||
details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
|
||
details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
|
||
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
|
||
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
|
||
.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
|
||
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
|
||
.admonitionblock>table td.icon{text-align:center;width:80px}
|
||
.admonitionblock>table td.icon img{max-width:none}
|
||
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
|
||
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
|
||
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
|
||
.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
|
||
.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
|
||
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
|
||
.exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}
|
||
.exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
|
||
.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
|
||
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
|
||
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
|
||
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
|
||
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
|
||
.listingblock>.content{position:relative}
|
||
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
|
||
.listingblock:hover code[data-lang]::before{display:block}
|
||
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
|
||
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
|
||
.listingblock pre.highlightjs{padding:0}
|
||
.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
|
||
.listingblock pre.prettyprint{border-width:0}
|
||
.prettyprint{background:#f7f7f8}
|
||
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
|
||
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
|
||
pre.prettyprint li code[data-lang]::before{opacity:1}
|
||
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
|
||
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
|
||
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
|
||
table.linenotable td.code{padding-left:.75em}
|
||
table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||
pre.pygments span.linenos{display:inline-block;margin-right:.75em}
|
||
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
|
||
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
|
||
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
|
||
.quoteblock blockquote{margin:0;padding:0;border:0}
|
||
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
|
||
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
|
||
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
|
||
.verseblock{margin:0 1em 1.25em}
|
||
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
|
||
.verseblock pre strong{font-weight:400}
|
||
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
|
||
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
|
||
.quoteblock .attribution br,.verseblock .attribution br{display:none}
|
||
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
|
||
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
|
||
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
|
||
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
|
||
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
|
||
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
|
||
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
|
||
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
|
||
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
|
||
p.tableblock:last-child{margin-bottom:0}
|
||
td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
|
||
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
|
||
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
|
||
table.grid-all>*>tr>*{border-width:1px}
|
||
table.grid-cols>*>tr>*{border-width:0 1px}
|
||
table.grid-rows>*>tr>*{border-width:1px 0}
|
||
table.frame-all{border-width:1px}
|
||
table.frame-ends{border-width:1px 0}
|
||
table.frame-sides{border-width:0 1px}
|
||
table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
|
||
table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
|
||
table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
|
||
table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
|
||
table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
|
||
th.halign-left,td.halign-left{text-align:left}
|
||
th.halign-right,td.halign-right{text-align:right}
|
||
th.halign-center,td.halign-center{text-align:center}
|
||
th.valign-top,td.valign-top{vertical-align:top}
|
||
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
|
||
th.valign-middle,td.valign-middle{vertical-align:middle}
|
||
table thead th,table tfoot th{font-weight:bold}
|
||
tbody tr th{background:#f7f8f7}
|
||
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
|
||
p.tableblock>code:only-child{background:none;padding:0}
|
||
p.tableblock{font-size:1em}
|
||
ol{margin-left:1.75em}
|
||
ul li ol{margin-left:1.5em}
|
||
dl dd{margin-left:1.125em}
|
||
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
|
||
li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
|
||
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
|
||
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
|
||
ul.unstyled,ol.unstyled{margin-left:0}
|
||
li>p:empty:only-child::before{content:"";display:inline-block}
|
||
ul.checklist>li>p:first-child{margin-left:-1em}
|
||
ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
|
||
ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
|
||
ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
|
||
ul.inline>li{margin-left:1.25em}
|
||
.unstyled dl dt{font-weight:400;font-style:normal}
|
||
ol.arabic{list-style-type:decimal}
|
||
ol.decimal{list-style-type:decimal-leading-zero}
|
||
ol.loweralpha{list-style-type:lower-alpha}
|
||
ol.upperalpha{list-style-type:upper-alpha}
|
||
ol.lowerroman{list-style-type:lower-roman}
|
||
ol.upperroman{list-style-type:upper-roman}
|
||
ol.lowergreek{list-style-type:lower-greek}
|
||
.hdlist>table,.colist>table{border:0;background:none}
|
||
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
|
||
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
|
||
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
|
||
td.hdlist2{word-wrap:anywhere}
|
||
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
|
||
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
|
||
.colist td:not([class]):first-child img{max-width:none}
|
||
.colist td:not([class]):last-child{padding:.25em 0}
|
||
.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
|
||
.imageblock.left{margin:.25em .625em 1.25em 0}
|
||
.imageblock.right{margin:.25em 0 1.25em .625em}
|
||
.imageblock>.title{margin-bottom:0}
|
||
.imageblock.thumb,.imageblock.th{border-width:6px}
|
||
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
|
||
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
|
||
.image.left{margin-right:.625em}
|
||
.image.right{margin-left:.625em}
|
||
a.image{text-decoration:none;display:inline-block}
|
||
a.image object{pointer-events:none}
|
||
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
|
||
sup.footnote a,sup.footnoteref a{text-decoration:none}
|
||
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
|
||
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
|
||
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
|
||
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
|
||
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
|
||
#footnotes .footnote:last-of-type{margin-bottom:0}
|
||
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
|
||
div.unbreakable{page-break-inside:avoid}
|
||
.big{font-size:larger}
|
||
.small{font-size:smaller}
|
||
.underline{text-decoration:underline}
|
||
.overline{text-decoration:overline}
|
||
.line-through{text-decoration:line-through}
|
||
.aqua{color:#00bfbf}
|
||
.aqua-background{background:#00fafa}
|
||
.black{color:#000}
|
||
.black-background{background:#000}
|
||
.blue{color:#0000bf}
|
||
.blue-background{background:#0000fa}
|
||
.fuchsia{color:#bf00bf}
|
||
.fuchsia-background{background:#fa00fa}
|
||
.gray{color:#606060}
|
||
.gray-background{background:#7d7d7d}
|
||
.green{color:#006000}
|
||
.green-background{background:#007d00}
|
||
.lime{color:#00bf00}
|
||
.lime-background{background:#00fa00}
|
||
.maroon{color:#600000}
|
||
.maroon-background{background:#7d0000}
|
||
.navy{color:#000060}
|
||
.navy-background{background:#00007d}
|
||
.olive{color:#606000}
|
||
.olive-background{background:#7d7d00}
|
||
.purple{color:#600060}
|
||
.purple-background{background:#7d007d}
|
||
.red{color:#bf0000}
|
||
.red-background{background:#fa0000}
|
||
.silver{color:#909090}
|
||
.silver-background{background:#bcbcbc}
|
||
.teal{color:#006060}
|
||
.teal-background{background:#007d7d}
|
||
.white{color:#bfbfbf}
|
||
.white-background{background:#fafafa}
|
||
.yellow{color:#bfbf00}
|
||
.yellow-background{background:#fafa00}
|
||
span.icon>.fa{cursor:default}
|
||
a span.icon>.fa{cursor:inherit}
|
||
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
|
||
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
|
||
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
|
||
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
|
||
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
|
||
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
|
||
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
|
||
.conum[data-value] *{color:#fff!important}
|
||
.conum[data-value]+b{display:none}
|
||
.conum[data-value]::after{content:attr(data-value)}
|
||
pre .conum[data-value]{position:relative;top:-.125em}
|
||
b.conum *{color:inherit!important}
|
||
.conum:not([data-value]):empty{display:none}
|
||
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
|
||
h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
|
||
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
|
||
p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}
|
||
p{margin-bottom:1.25rem}
|
||
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
|
||
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
|
||
.print-only{display:none!important}
|
||
@page{margin:1.25cm .75cm}
|
||
@media print{*{box-shadow:none!important;text-shadow:none!important}
|
||
html{font-size:80%}
|
||
a{color:inherit!important;text-decoration:underline!important}
|
||
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
|
||
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
|
||
abbr[title]{border-bottom:1px dotted}
|
||
abbr[title]::after{content:" (" attr(title) ")"}
|
||
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
|
||
thead{display:table-header-group}
|
||
svg{max-width:100%}
|
||
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
|
||
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
|
||
#header,#content,#footnotes,#footer{max-width:none}
|
||
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
|
||
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
|
||
body.book #header{text-align:center}
|
||
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
|
||
body.book #header .details{border:0!important;display:block;padding:0!important}
|
||
body.book #header .details span:first-child{margin-left:0!important}
|
||
body.book #header .details br{display:block}
|
||
body.book #header .details br+span::before{content:none!important}
|
||
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
|
||
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
|
||
.listingblock code[data-lang]::before{display:block}
|
||
#footer{padding:0 .9375em}
|
||
.hide-on-print{display:none!important}
|
||
.print-only{display:block!important}
|
||
.hide-for-print{display:none!important}
|
||
.show-for-print{display:inherit!important}}
|
||
@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
|
||
.sect1{padding:0!important}
|
||
.sect1+.sect1{border:0}
|
||
#footer{background:none}
|
||
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
|
||
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
|
||
</style>
|
||
</head>
|
||
<body class="article toc2 toc-left">
|
||
<div id="header">
|
||
<h1>Boost.OpenMethod</h1>
|
||
<div class="details">
|
||
<span id="author" class="author">Jean-Louis Leroy</span><br>
|
||
</div>
|
||
<div id="toc" class="toc2">
|
||
<div id="toctitle">Table of Contents</div>
|
||
<ul class="sectlevel1">
|
||
<li><a href="#introduction">Introduction</a></li>
|
||
<li><a href="#tutorials">Tutorials</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#tutorials_hello_world">Hello World</a></li>
|
||
<li><a href="#tutorials_multiple_dispatch">Multiple Dispatch</a></li>
|
||
<li><a href="#tutorials_headers_and_namespaces">Headers and Namespaces</a></li>
|
||
<li><a href="#tutorials_friendship">Friendship</a></li>
|
||
<li><a href="#tutorials_performance">Performance</a></li>
|
||
<li><a href="#tutorials_smart_pointers">Smart Pointers</a></li>
|
||
<li><a href="#tutorials_alternatives_to_virtual_ptr">Alternatives to virtual_ptr</a></li>
|
||
<li><a href="#tutorials_core_api">Core API</a></li>
|
||
<li><a href="#tutorials_policies_and_policys">Policies and Facets</a></li>
|
||
<li><a href="#tutorials_error_handling">Error Handling</a></li>
|
||
<li><a href="#tutorials_custom_rtti">Custom RTTI</a></li>
|
||
<li><a href="#tutorials_deferred_rtti">Deferred RTTI</a></li>
|
||
<li><a href="#tutorials_dynamic_loading">Dynamic Loading</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#tutorials_reference">Reference</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#ref_overview">Overview</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_requirements">Requirements</a></li>
|
||
<li><a href="#ref_installation">Installation</a></li>
|
||
<li><a href="#ref_namespaces">Namespaces</a></li>
|
||
<li><a href="#ref_headers">Headers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD">BOOST_OPENMETHOD</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis">Synopsis</a></li>
|
||
<li><a href="#ref_description">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_OVERRIDE">BOOST_OPENMETHOD_OVERRIDE</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_2">Synopsis</a></li>
|
||
<li><a href="#ref_description_2">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_INLINE_OVERRIDE">BOOST_OPENMETHOD_INLINE_OVERRIDE</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_3">Synopsis</a></li>
|
||
<li><a href="#ref_description_3">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_boost_openmethod_declare_overrider">BOOST_OPENMETHOD_DECLARE_OVERRIDER</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_4">Synopsis</a></li>
|
||
<li><a href="#ref_description_4">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_boost_openmethod_define_overrider">BOOST_OPENMETHOD_DEFINE_OVERRIDER</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_5">Synopsis</a></li>
|
||
<li><a href="#ref_description_5">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_boost_openmethod_overrider">BOOST_OPENMETHOD_OVERRIDER</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_6">Synopsis</a></li>
|
||
<li><a href="#ref_description_6">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_ID">BOOST_OPENMETHOD_ID</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_7">Synopsis</a></li>
|
||
<li><a href="#ref_description_7">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_boost_openmethod_guide">BOOST_OPENMETHOD_GUIDE</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_8">Synopsis</a></li>
|
||
<li><a href="#ref_description_8">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_boost_openmethod_overriders">BOOST_OPENMETHOD_OVERRIDERS</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_9">Synopsis</a></li>
|
||
<li><a href="#ref_description_9">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_REGISTER">BOOST_OPENMETHOD_REGISTER</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_10">Synopsis</a></li>
|
||
<li><a href="#ref_description_10">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_CLASSES">BOOST_OPENMETHOD_CLASSES</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_11">Synopsis</a></li>
|
||
<li><a href="#ref_description_11">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#BOOST_OPENMETHOD_DEFAULT_REGISTRY">BOOST_OPENMETHOD_DEFAULT_REGISTRY</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_description_12">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_initialize">initialize</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_12">Synopsis</a></li>
|
||
<li><a href="#ref_description_13">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_finalize">finalize</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_13">Synopsis</a></li>
|
||
<li><a href="#ref_description_14">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_type_id">type_id</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_14">Synopsis</a></li>
|
||
<li><a href="#ref_description_15">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_vptr_type">vptr_type</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_15">Synopsis</a></li>
|
||
<li><a href="#ref_description_16">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#ref_method">method</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_16">Synopsis</a></li>
|
||
<li><a href="#ref_description_17">Description</a></li>
|
||
<li><a href="#ref_members">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#method_override">method::override</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#ref_synopsis_17">Synopsis</a></li>
|
||
<li><a href="#ref_description_18">Description</a></li>
|
||
<li><a href="#ref_members_2">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr">virtual_ptr</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description">Description</a></li>
|
||
<li><a href="#virtual_ptr_members">Members</a></li>
|
||
<li><a href="#virtual_ptr_deduction_guide">Deduction guide</a></li>
|
||
<li><a href="#virtual_ptr_non_members">Non-members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_virtual_traits">virtual_traits</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_2">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_2">Description</a></li>
|
||
<li><a href="#virtual_ptr_specializations">Specializations</a></li>
|
||
<li><a href="#virtual_ptr_members_2">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_use_classes">use_classes</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_3">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_3">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_3">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_virtual">virtual_</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_4">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_4">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_inplace_vptr">inplace_vptr</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_5">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_5">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_4">Members</a></li>
|
||
<li><a href="#virtual_ptr_synopsis_6">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_6">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_domain">domain</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_7">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_7">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_5">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_basic_policy">basic_policy</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_8">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_headers">Headers</a></li>
|
||
<li><a href="#virtual_ptr_description_8">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_6">Members</a></li>
|
||
<li><a href="#virtual_ptr_non_members_2">Non-members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_policy">policy</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_9">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_9">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_7">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_rtti">rtti</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_10">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_10">Description</a></li>
|
||
<li><a href="#virtual_ptr_requirements">Requirements</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_std_rtti">std_rtti</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_11">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_11">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_8">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_deferred_static_rtti">deferred_static_rtti</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_12">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_12">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_minimal_rtti">minimal_rtti</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_13">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_13">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_9">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_extern_vptr">extern_vptr</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_14">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_14">Description</a></li>
|
||
<li><a href="#virtual_ptr_requirements_2">Requirements</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_indirect_vptr">indirect_vptr</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_15">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_15">Description</a></li>
|
||
<li><a href="#virtual_ptr_requirements_3">Requirements</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_vptr_vector">vptr_vector</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_16">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_16">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_10">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_vptr_map">vptr_map</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_17">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_17">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_11">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_type_hash">type_hash</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_18">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_18">Description</a></li>
|
||
<li><a href="#virtual_ptr_requirements_4">Requirements</a></li>
|
||
<li><a href="#virtual_ptr_hash_type_id">hash_type_id</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_fast_perfect_hash">fast_perfect_hash</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_19">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_19">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_12">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_error_handler">error_handler</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_20">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_20">Description</a></li>
|
||
<li><a href="#virtual_ptr_requirements_5">Requirements</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_default_error_handler">default_error_handler</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_21">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_21">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_13">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_throw_error_handler">throw_error_handler</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_22">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_22">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_14">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_basic_error_output">basic_error_output</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_23">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_23">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_15">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_basic_trace_output">basic_trace_output</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_synopsis_24">Synopsis</a></li>
|
||
<li><a href="#virtual_ptr_description_24">Description</a></li>
|
||
<li><a href="#virtual_ptr_members_16">Members</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#virtual_ptr_restrictedoutputstream">LightweightOutputStream</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#virtual_ptr_description_25">Description</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div id="content">
|
||
<div class="sect1">
|
||
<h2 id="introduction">Introduction</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Open-methods are similar to virtual functions, but they are not required to be
|
||
members of a class. By being both free and virtual, they provide a solution to
|
||
the Expression Problem:</p>
|
||
</div>
|
||
<div class="quoteblock">
|
||
<blockquote>
|
||
<div class="paragraph">
|
||
<p>Given a set of types, and a set of operations on these types, is it possible
|
||
to add new operations on the existing types, and new types to the existing
|
||
operations, without modifying existing code?</p>
|
||
</div>
|
||
</blockquote>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Open-methods also address the banana-gorilla-shared problem:</p>
|
||
</div>
|
||
<div class="quoteblock">
|
||
<blockquote>
|
||
<div class="paragraph">
|
||
<p>The problem with object-oriented languages is they’ve got all this implicit
|
||
environment that they carry around with them. You wanted a banana but what you
|
||
got was a gorilla holding the banana and the entire shared. — Joe Armstrong,
|
||
creator of Erlang progamming language</p>
|
||
</div>
|
||
</blockquote>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>As a bonus, open-methods can take more than one argument into account when
|
||
selecting the appropriate function to call - aka multiple dispatch. For that
|
||
reason, open-methods are often called multi-methods, but that term is
|
||
misleading, as it suggests that the feature is useful only when multiple
|
||
dispatch is needed. In reality,
|
||
<a href="https://openaccess.wgtn.ac.nz/articles/thesis/Multiple_Dispatch_in_Practice/16959112/1">it
|
||
has been observed</a> that, in large systems written in languages that support
|
||
multi-methods, most methods use single-dispatch. The real benefit is in the
|
||
solution to the Expression Problem.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Open-methods were introduced by the Common Lisp Object System, and they are
|
||
native to many languages: Clojure, Julia, Dylan, TADS, Cecil, Diesel, Nice, etc.
|
||
Bjarne Stroustrup wanted open-methods in C++ almost from the beginning. In D&E
|
||
he writes:</p>
|
||
</div>
|
||
<div class="quoteblock">
|
||
<blockquote>
|
||
<div class="paragraph">
|
||
<p>I repeatedly considered a mechanism for a virtual function call based on more
|
||
than one object, often called multi-methods. I rejected multi-methods with
|
||
regret because I liked the idea, but couldn’t find an acceptable form under
|
||
which to accept it. […​] Multi-methods is one of the interesting what-ifs of
|
||
C++. Could I have designed and implemented them well enough at the time? Would
|
||
their applications have been important enough to warrant the effort? What other
|
||
work might have been left undone to provide the time to design and implement
|
||
multi-methods? Since about 1985, I have always felt some twinge of regret for
|
||
not providing multi-methods (Stroustrup, 1994, The Design and Evolution of
|
||
C++, 13.8).</p>
|
||
</div>
|
||
</blockquote>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Circa 2007, he and his PhD students Peter Pirkelbauer and Yuriy Solodkyy wrote a
|
||
series of papers and a prototype implementation based on the EDG compiler.
|
||
Unfortunately, open-methods never made it into the standard. Stroustrup bemoans,
|
||
in a more recent paper:</p>
|
||
</div>
|
||
<div class="quoteblock">
|
||
<blockquote>
|
||
<div class="paragraph">
|
||
<p>In retrospect, I don’t think that the object-oriented notation (e.g., x.f(y))
|
||
should ever have been introduced. The traditional mathematical notation f(x,y)
|
||
is sufficient. As a side benefit, the mathematical notation would naturally have
|
||
given us multi-methods, thereby saving us from the visitor pattern workaround
|
||
(Stroustrup, 2020, Thriving in a Crowded and ChangingWorld: C++ 2006–2020).</p>
|
||
</div>
|
||
</blockquote>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This library implements the features described in the
|
||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf">N2216 paper</a>,
|
||
with some extensions:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>a mechanism for calling the next most specialized overrider</p>
|
||
</li>
|
||
<li>
|
||
<p>support for smart pointers</p>
|
||
</li>
|
||
<li>
|
||
<p>customization points for RTTI, error handling, tracing, smart pointers…​</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Multiple and virtual inheritance are supported, with the exception of repeated
|
||
inheritance.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="tutorials">Tutorials</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="tutorials_hello_world">Hello World</h3>
|
||
<div class="paragraph">
|
||
<p>Consider the following program, intended to demonstrate the basics of virtual
|
||
functions:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <memory>
|
||
|
||
struct Animal {
|
||
Animal(std::string name) : name(name) {}
|
||
virtual ~Animal() = default;
|
||
virtual void poke(std::ostream&) = 0;
|
||
std::string name;
|
||
};
|
||
|
||
struct Cat : Animal {
|
||
using Animal::Animal;
|
||
|
||
void poke(std::ostream& os) override {
|
||
os << name << " hisses";
|
||
}
|
||
};
|
||
|
||
struct Dog : Animal {
|
||
using Animal::Animal;
|
||
|
||
void poke(std::ostream& os) override {
|
||
os << name << " barks";
|
||
}
|
||
};
|
||
|
||
struct Bulldog : Dog {
|
||
using Dog::Dog;
|
||
|
||
void poke(std::ostream& os) override {
|
||
Dog::poke(os);
|
||
os << " and bites back";
|
||
}
|
||
};
|
||
|
||
auto main() -> int {
|
||
std::unique_ptr<Animal> a(new Cat("Felix"));
|
||
std::unique_ptr<Animal> b(new Dog("Snoopy"));
|
||
std::unique_ptr<Animal> c(new Bulldog("Hector"));
|
||
|
||
a->poke(std::cout); // prints "Felix hisses"
|
||
std::cout << ".\n";
|
||
|
||
b->poke(std::cout); // prints "Snoopy barks"
|
||
std::cout << ".\n";
|
||
|
||
c->poke(std::cout); // prints "Hector barks and bites back"
|
||
std::cout << ".\n";
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We are going to rewrite this using open-methods.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>First we remove the <code>poke</code> virtual functions from the domain classes:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <string>
|
||
|
||
struct Animal {
|
||
Animal(std::string name) : name(name) {}
|
||
std::string name;
|
||
virtual ~Animal() = default;
|
||
};
|
||
|
||
struct Cat : Animal {
|
||
using Animal::Animal;
|
||
};
|
||
|
||
struct Dog : Animal {
|
||
using Animal::Animal;
|
||
};
|
||
|
||
struct Bulldog : Dog {
|
||
using Dog::Dog;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that the Animal classes do not depend on iostreams anymore. This is a major
|
||
advantage of open-methods over virtual functions: they make it possible to
|
||
better organize dependencies.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s implement <code>poke</code>. First we need to include the library’s main header. It
|
||
defines a few macros, and injects a name - <code>virtual_ptr</code> - in the global
|
||
namespace.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <boost/openmethod.hpp>
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
BOOST_OPENMETHOD(
|
||
poke, // method name
|
||
(std::ostream&, virtual_ptr<Animal>), // method signature
|
||
void); // return type</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This defines a free function called <code>poke</code>, which takes two arguments. The first
|
||
is the <code>ostream</code>. The second argument corresponds to the implicit <code>this</code> pointer
|
||
in a virtual function. It is now an explicit argument. Just like with virtual
|
||
functions, the exact function to execute is selected on the basis of the
|
||
argument’s <em>dynamic</em> type.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Unlike virtual functions, there is no such thing as a pure open-method that
|
||
would make a class abstract. It is not possible to determine if an overrider is
|
||
available from looking at just the current translation unit.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s add overriders for <code>Cat</code> and <code>Dog</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, // method name
|
||
(std::ostream & os, virtual_ptr<Cat> cat), // overrider signature
|
||
void) { // return type
|
||
os << cat->name << " hisses"; // overrider body
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
|
||
os << dog->name << " barks";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>Bulldog::poke</code> calls the <code>poke</code> it overrides in its <code>Dog</code> base. The equivalent
|
||
for open-methods is <code>next</code>, a function that is available only inside the body of
|
||
an overrider. It calls the next most specific overrider, i.e. what would have
|
||
been called if the overrider did not exist.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Bulldog> dog), void) {
|
||
next(os, dog); // call base overrider
|
||
os << " and bites back";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>All classes involved in open-method calls need to be registered using the
|
||
<code>BOOST_OPENMETHOD_CLASSES</code> macro:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, Bulldog);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Classes can be registered incrementally, as long as all the direct bases of a
|
||
class are listed with it in some call(s) to <code>BOOST_OPENMETHOD_CLASSES</code>. For
|
||
example, <code>Bulldog</code> can be added in a second call, as long as <code>Dog</code> is listed as
|
||
well:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// in animals.cpp
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||
|
||
// in bulldog.cpp
|
||
BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>boost::openmethod::initialize();</code> must be called before any open-method call.
|
||
It builds the dispatch tables. Typically this is done in <code>main</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <boost/openmethod/compiler.hpp>
|
||
// only needed in the file that calls boost::openmethod::initialize()
|
||
|
||
auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
// ...
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We call <code>poke</code> like any ordinary function. We can pass it the animals by
|
||
reference, because <code>virtual_ptr</code> has a conversion constructor for that:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++"> std::unique_ptr<Animal> felix(new Cat("Felix"));
|
||
std::unique_ptr<Animal> snoopy(new Dog("Snoopy"));
|
||
std::unique_ptr<Animal> hector(new Bulldog("Hector"));
|
||
|
||
poke(std::cout, *felix); // Felix hisses
|
||
std::cout << ".\n";
|
||
|
||
poke(std::cout, *snoopy); // Snoopy barks
|
||
std::cout << ".\n";
|
||
|
||
poke(std::cout, *hector); // Hector barks and bites
|
||
std::cout << ".\n";</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_multiple_dispatch">Multiple Dispatch</h3>
|
||
<div class="paragraph">
|
||
<p>A method can have more than one <code>virtual_ptr</code> parameter. For example:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD(
|
||
encounter,
|
||
(std::ostream&, virtual_ptr<Animal>, virtual_ptr<Animal>), void);
|
||
|
||
// 'encounter' catch-all implementation.
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter,
|
||
(std::ostream & os, virtual_ptr<Animal> a, virtual_ptr<Animal> b), void) {
|
||
os << a->name << " and " << b->name << " ignore each other";
|
||
}
|
||
|
||
// Add definitions for specific pairs of animals.
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter,
|
||
(std::ostream & os, virtual_ptr<Dog> /*dog1*/, virtual_ptr<Dog> /*dog2*/), void) {
|
||
os << "Both wag tails";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter, (std::ostream & os, virtual_ptr<Dog> dog, virtual_ptr<Cat> cat),
|
||
void) {
|
||
os << dog->name << " chases " << cat->name;
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter, (std::ostream & os, virtual_ptr<Cat> cat, virtual_ptr<Dog> dog),
|
||
void) {
|
||
os << cat->name << " runs away from " << dog->name;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// cat and dog
|
||
encounter(std::cout, *felix, *snoopy); // Felix runs away from Snoopy
|
||
std::cout << ".\n";
|
||
|
||
// dog and cat
|
||
encounter(std::cout, *snoopy, *felix); // Snoopy chases Felix
|
||
std::cout << ".\n";
|
||
|
||
// dog and dog
|
||
encounter(std::cout, *snoopy, *hector); // Both wag tails
|
||
std::cout << ".\n";
|
||
|
||
// cat and cat
|
||
std::unique_ptr<Animal> tom(new Cat("Tom"));
|
||
encounter(std::cout, *felix, *tom); // Felix and Tom ignore each other
|
||
std::cout << ".\n";</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The appropriate overrider is selected using a process similar to overload
|
||
resolution, with fallback options. If one overrider is more specialized than all
|
||
the others, call it. Otherwise, the return type is used as a tie-breaker, <em>if</em>
|
||
it is covariant with the return type of the base method. If there is still no
|
||
unique best overrider, one of the best overriders is chosen arbitrarily.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_headers_and_namespaces">Headers and Namespaces</h3>
|
||
<div class="paragraph">
|
||
<p>Most real-life programs will be organized in multiple files and multiple
|
||
namespaces. OpenMethod interacts with headers and namespaces naturally, if
|
||
using-directives are avoided. In that case, there are a few things to be aware
|
||
of.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s break the Animals example into headers and namespaces. First we put
|
||
<code>Animal</code> in its own header and namespace:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// animal.hpp
|
||
|
||
#ifndef ANIMAL_HPP
|
||
#define ANIMAL_HPP
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <string>
|
||
|
||
namespace animals {
|
||
|
||
struct Animal {
|
||
Animal(std::string name) : name(name) {
|
||
}
|
||
std::string name;
|
||
virtual ~Animal() = default;
|
||
};
|
||
|
||
BOOST_OPENMETHOD(
|
||
poke, (std::ostream&, boost::openmethod::virtual_ptr<Animal>), void);
|
||
|
||
} // namespace animals
|
||
|
||
#endif // ANIMAL_HPP</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD</code> can be placed in a header file. It adds several constructs to
|
||
the current namespace:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>It declares (but does not define) a <code>struct</code> named after the method.</p>
|
||
</li>
|
||
<li>
|
||
<p>It declares (but does not define) a <em>guide</em> function. It is also named after
|
||
the method, and it has the same signature (with the <code>virtual_</code> decorators
|
||
stripped). It is used to match methods and overriders. It is never defined and
|
||
it is "called" only in a non-evaluated context.</p>
|
||
</li>
|
||
<li>
|
||
<p>It defines an inline function with the same name and signature as the
|
||
method (with the <code>virtual_</code> decorators stripped).</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Next, let’s implement the <code>Cat</code> class, and a derived class, <code>Cheetah</code>, in the
|
||
<code>felines</code> namespace:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// felines.hpp
|
||
|
||
#ifndef FELINES_HPP
|
||
#define FELINES_HPP
|
||
|
||
#include "animal.hpp"
|
||
|
||
namespace felines {
|
||
|
||
struct Cat : animals::Animal {
|
||
using Animal::Animal;
|
||
};
|
||
|
||
struct Cheetah : Cat {
|
||
using Cat::Cat;
|
||
};
|
||
|
||
} // namespace felines
|
||
|
||
#endif // FELINES_HPP</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// cat.cpp
|
||
|
||
#include <iostream>
|
||
#include <boost/openmethod.hpp>
|
||
|
||
#include "cat.hpp"
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
namespace felines {
|
||
|
||
BOOST_OPENMETHOD_CLASSES(animals::Animal, Cat, Cheetah);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Cat> cat), void) {
|
||
os << cat->name << " hisses";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Cheetah> cat), void) {
|
||
BOOST_OPENMETHOD_OVERRIDER(
|
||
poke, (std::ostream & os, virtual_ptr<Cat> dog), void)::fn(os, cat);
|
||
os << " and runs away";
|
||
}
|
||
|
||
} // namespace felines</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_CLASSES</code> should be placed in an implementation file. It can
|
||
also go in a header file, but this wastes space, as the same registrar will be
|
||
created in every translation unit that includes the header. It doesn’t matter
|
||
which namespace the macro is called in. It can take be used with any class name
|
||
in scope, or with qualified names.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_OVERRIDE</code> uses the guide function declared by
|
||
<code>BOOST_OPENMETHOD</code> to locate a method that can be called with the same arguments
|
||
as the overrider itself. It "calls" the guide function in a non-evaluated
|
||
context, passing it a <code>std::ostream&</code> and a <code>virtual_ptr<Cat></code>. The return type
|
||
of the guide function is the method to add the overrider to. Exactly one guide
|
||
function must match. The normal rules of overload resolution apply. In that
|
||
case, the guide function is found via argument dependant lookup (ADL).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The macro adds several constructs to the current namespace:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>It declares (but does not define) a <code>struct</code> template with one type parameter,
|
||
named after the method. The template acts like a container for overriders.</p>
|
||
</li>
|
||
<li>
|
||
<p>It specializes the template for the signature of the overrider. Inside the
|
||
struct, it defines the <code>next</code> and <code>has_next</code> members, and a static function
|
||
called <code>fn</code>. The block following the macro is the body of the <code>fn</code> function.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>It follows that <code>BOOST_OPENMETHOD_OVERRIDE</code> should be placed in an
|
||
implementation file. <code>BOOST_OPENMETHOD_INLINE_OVERRIDE</code> works like
|
||
<code>BOOST_OPENMETHOD_OVERRIDE</code>, but it defines the <code>fn</code> function as inline, so it
|
||
can be used in a header file.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The overrider for Cats can be accessed in the same translation unit, after it
|
||
has been defined, using the <code>BOOST_OPENMETHOD_OVERRIDER</code> macro. It expands to
|
||
the specialization of the overrider container for the overrider’s signature. We
|
||
call the static <code>fn</code> function to call the overrider.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
The Cheetah overrider calls the specific overrider for <code>Cat</code>, for
|
||
illustration purpose. It is usually better to call <code>next</code> instead.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s implement the <code>Dog</code> class, in the <code>canines</code> namespace. This time we want
|
||
the overrider to be accessible in other translation units. We can declare an
|
||
overrider with <code>BOOST_OPENMETHOD_DECLARE_OVERRIDER</code>, without actually defining
|
||
the static function <code>fn</code> just yet.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#ifndef CANINES_HPP
|
||
#define CANINES_HPP
|
||
|
||
#include <iosfwd>
|
||
#include <boost/openmethod.hpp>
|
||
|
||
#include "animal.hpp"
|
||
|
||
namespace canines {
|
||
|
||
struct Dog : animals::Animal {
|
||
using Animal::Animal;
|
||
};
|
||
|
||
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
|
||
poke, (std::ostream & os, boost::openmethod::virtual_ptr<Dog> dog), void);
|
||
|
||
} // namespace canines
|
||
|
||
#endif // CANINES_HPP</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Unlike function declarations, which can occur multiple times in a TU, an
|
||
overrider declaration cannot. For example, this is illegal:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_DECLARE_OVERRIDER(
|
||
poke, (std::ostream&, virtual_ptr<Dog>), void);
|
||
|
||
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
|
||
poke, (std::ostream&, virtual_ptr<Dog>), void);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now we use <code>BOOST_OPENMETHOD_DEFINE_OVERRIDER</code> to define the overrider:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <boost/openmethod.hpp>
|
||
|
||
#include "dog.hpp"
|
||
|
||
namespace canines {
|
||
|
||
BOOST_OPENMETHOD_CLASSES(animals::Animal, Dog);
|
||
|
||
BOOST_OPENMETHOD_DEFINE_OVERRIDER(
|
||
poke, (std::ostream & os, boost::openmethod::virtual_ptr<Dog> dog), void) {
|
||
os << dog->name << " barks";
|
||
}
|
||
|
||
} // namespace canines</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s look at the main program now. It derived <code>Bulldog</code> from <code>Dog</code> and provides
|
||
an overrider for the new class:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
#include "animal.hpp"
|
||
#include "cat.hpp"
|
||
#include "dog.hpp"
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
struct Bulldog : canines::Dog {
|
||
using Dog::Dog;
|
||
};
|
||
|
||
BOOST_OPENMETHOD_CLASSES(canines::Dog, Bulldog);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Bulldog> dog), void) {
|
||
canines::BOOST_OPENMETHOD_OVERRIDER(
|
||
poke, (std::ostream & os, virtual_ptr<canines::Dog> dog),
|
||
void)::fn(os, dog);
|
||
os << " and bites back";
|
||
}
|
||
|
||
auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
|
||
std::unique_ptr<animals::Animal> felix(new felines::Cat("Felix"));
|
||
std::unique_ptr<animals::Animal> azaad(new felines::Cheetah("Azaad"));
|
||
std::unique_ptr<animals::Animal> snoopy(new canines::Dog("Snoopy"));
|
||
std::unique_ptr<animals::Animal> hector(new Bulldog("Hector"));
|
||
|
||
poke(std::cout, *felix); // Felix hisses
|
||
std::cout << ".\n";
|
||
|
||
poke(std::cout, *azaad); // Azaad hisses and runs away
|
||
std::cout << ".\n";
|
||
|
||
poke(std::cout, *snoopy); // Snoopy barks
|
||
std::cout << ".\n";
|
||
|
||
poke(std::cout, *hector); // Hector barks and bites
|
||
std::cout << ".\n";
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Again ADL plays a role: it helps the overrider (and <code>main</code>) to locate the <code>poke</code>
|
||
method.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This example is the "happy scenario", where namespaces are used conservatively.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>OVERRIDE</code> macros don’t interact well with <code>using</code> directives. For example
|
||
this code:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">using namespace animals;
|
||
using namespace canines;
|
||
using namespace felines;
|
||
|
||
struct Bulldog : Dog {
|
||
using Dog::Dog;
|
||
};
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Bulldog> dog), void) {
|
||
next(os, dog);
|
||
os << " and bites back";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>…​will fail to compile, with an error like "reference to
|
||
'poke_boost_openmethod_overriders' is ambiguous". That is because the overrider
|
||
containers exist in both the canines and felines namespaces, with the same name.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, the names passed as first arguments to the BOOST_OPENMETHOD and
|
||
BOOST_OPENMETHOD_OVERRIDE macros must be identifiers. Qualified names are not
|
||
allowed. Consider:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">using animals::Animal;
|
||
|
||
namespace app_specific_behavior {
|
||
|
||
BOOST_OPENMETHOD(
|
||
meet, (std::ostream&, virtual_ptr<Animal>, virtual_ptr<Animal>), void);
|
||
|
||
} // namespace app_specific_behavior
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
meet, (std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
|
||
os << "ignore";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here, the guide function cannot be found, even via ADL. We get an error like
|
||
"use of undeclared identifier 'meet_boost_openmethod_guide'". How do we solve
|
||
this? We might be tempted to use a qualified name:
|
||
<code>app_specific_behavior::meet</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_OVERRIDE(
|
||
app_specific_behavior::meet,
|
||
(std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
|
||
os << "ignore";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>But <code>BOOST_OPENMETHOD_OVERRIDE</code> also uses the name to derive the overrider
|
||
container’s name, using preprocessor token pasting, resulting in an invalid
|
||
declaration error.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We need to do is to make <code>BOOST_OPENMETHOD_OVERRIDE</code> "see" the guide function.
|
||
Its name is returned by macro <code>BOOST_OPENMETHOD_GUIDE(NAME)</code>. We can use a
|
||
using-declaration to bring the guide function into the current scope:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">using app_specific_behavior::BOOST_OPENMETHOD_GUIDE(meet);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
meet, (std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
|
||
os << "ignore";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_friendship">Friendship</h3>
|
||
<div class="paragraph">
|
||
<p>We can use overrider containers to grant friendship to a specific overrider, or
|
||
to all the overriders of a method. The name of the container template is
|
||
returned by <code>BOOST_OPENMETHOD_OVERRIDERS</code>. The template argument for a
|
||
specialization is the signature of the overrider. For example, the overrider of
|
||
<code>poke</code> for <code>Cat</code> is:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_OVERRIDERS(poke)<
|
||
void(std::ostream& os, virtual_ptr<Cat> cat)>::fn;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can thus grant friendship to all the overriders of <code>poke</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">class Cat;
|
||
class Dog;
|
||
|
||
class Animal {
|
||
// ...
|
||
private:
|
||
std::string name;
|
||
|
||
template<typename> friend struct BOOST_OPENMETHOD_OVERRIDERS(poke);
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Be aware, though, that the overriders of <em>any</em> method called <code>poke</code> - with any
|
||
signature - are granted friendship.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can also befriend individual overriders:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">class Cat;
|
||
class Dog;
|
||
|
||
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
|
||
|
||
class Animal {
|
||
// ...
|
||
private:
|
||
std::string name;
|
||
|
||
friend struct BOOST_OPENMETHOD_OVERRIDERS(poke)<void(std::ostream&, virtual_ptr<Cat>)>;
|
||
friend struct BOOST_OPENMETHOD_OVERRIDERS(poke)<void(std::ostream&, virtual_ptr<Dog>)>;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_performance">Performance</h3>
|
||
<div class="paragraph">
|
||
<p>Open-methods are almost as fast as ordinary virtual member functions when
|
||
compiled with optimization.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>clang compiles the following code:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">void call_poke_via_ref(std::ostream& os, Animal& a) {
|
||
poke(os, a);
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>…​to this on the x64 architecture (variable names have been shortened for
|
||
readability):</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="asm">mov rax, qword ptr [rsi]
|
||
mov rdx, qword ptr [rip + mult]
|
||
imul rdx, qword ptr [rax - 8]
|
||
movzx ecx, byte ptr [rip + shift]
|
||
shr rdx, cl
|
||
mov rax, qword ptr [rip + vptrs]
|
||
mov rax, qword ptr [rax + 8*rdx]
|
||
mov rcx, qword ptr [rip + poke::slots_strides]
|
||
mov rax, qword ptr [rax + 8*rcx]
|
||
jmp rax</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>llvm-mca estimates a throughput of 4 cycles per dispatch. Comparatively, calling
|
||
a native virtual functions takes one cycle. However, the difference is amortized
|
||
by the time spent passing the arguments and returning from the function; plus,
|
||
of course, executing the body of the function.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Micro benchmarks suggest that dispatching an open-methods with a single virtual
|
||
argument is between 30% and 50% slower than calling the equivalent virtual
|
||
function, with an empty body and no other arguments.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, <code>call_poke</code> does two things: it constructs a <code>virtual_ptr<Animal></code> from
|
||
an <code>Animal&</code>; and then it calls the method. The construction of the
|
||
<code>virtual_ptr</code> is the costly part, as it involves a hash table lookup. Once that
|
||
price has been paid, the <code>virtual_ptr</code> can be used multiple times. It is passed
|
||
to the overrider, which can make further method calls through it. It can be
|
||
stored in variables in place of plain pointers.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s look at another example: an AST for an arithmetic calculator:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
struct Node {
|
||
virtual ~Node() {}
|
||
};
|
||
|
||
struct Literal : Node {
|
||
explicit Literal(int value) : value(value) {}
|
||
|
||
int value;
|
||
};
|
||
|
||
struct Plus : Node {
|
||
Plus(virtual_ptr<Node> left, virtual_ptr<Node> right)
|
||
: left(left), right(right) {}
|
||
|
||
virtual_ptr<Node> left, right;
|
||
};
|
||
|
||
struct Negate : Node {
|
||
explicit Negate(virtual_ptr<Node> node) : child(node) {}
|
||
|
||
virtual_ptr<Node> child;
|
||
};
|
||
|
||
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
|
||
return node->value;
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Plus> node), int) {
|
||
return value(node->left) + value(node->right);
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
|
||
return -value(node->child);
|
||
}
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
|
||
|
||
auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
|
||
Literal one(1), two(2);
|
||
Plus sum(one, two);
|
||
Negate neg(sum);
|
||
|
||
std::cout << value(neg) << "\n"; // -3
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>Negate</code> overrider compiles to:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="asm">mov rdi, qword ptr [rsi + 8]
|
||
mov rsi, qword ptr [rsi + 16]
|
||
|
||
mov rax, qword ptr [rip + value::slots_strides]
|
||
call qword ptr [rdi + 8*rax]
|
||
|
||
neg eax
|
||
pop rcx</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The first two instructions read the <code>virtual_ptr</code> from <code>this</code> - placing its
|
||
content in registers <code>rdi</code> and <code>rsi</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The next two instructions are the method call proper. According to llvm-mca,
|
||
they take one cycle - the same as a native virtual function call.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>When we create the <code>Plus</code> and <code>Negate</code> nodes, we call the conversion
|
||
constructors of <code>virtual_ptr<Node></code>, which occur the cost of hash table lookups.
|
||
However, in this example, we know the exact types of the objects. In that case,
|
||
we can use <code>final_virtual_ptr</code> to construct the <code>virtual_ptr</code> using a single
|
||
instruction. For example:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">Literal one(1);
|
||
Negate neg(boost::openmethod::final_virtual_ptr(one));</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>…​compiles to:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="asm">;; construct Literal
|
||
lea rax, [rip + vtable for Literal+16]
|
||
mov qword ptr [rsp], rax
|
||
mov dword ptr [rsp+8], 1
|
||
|
||
;; construct Negate
|
||
mov rax, qword ptr [rip+static_vptr<Literal>] ; address of openmethod v-table
|
||
lea rcx, [rip+vtable for Negate+16] ; address of native v-table
|
||
mov qword ptr [rsp+16], rcx ; set native v-table
|
||
mov qword ptr [rsp+24], rax ; set openmethod v-table
|
||
mov rax, rsp ; address of 'one'
|
||
mov qword ptr [rsp+32], rax ; set vptr object pointer to 'one'</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>final_virtual_ptr</code> does not require its argument to have a polymorphic type.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_smart_pointers">Smart Pointers</h3>
|
||
<div class="paragraph">
|
||
<p><code>virtual_ptr</code> can also be used in combination with smart pointers.
|
||
<code>virtual_ptr<std::shared_ptr<Class>></code> (aliased to <code>shared_virtual_ptr<Class></code>)
|
||
and <code>virtual_ptr<std::unique_ptr<Class>></code> (aliased to
|
||
<code>unique_virtual_ptr<Class></code>) deliver the convenience of automatic memory
|
||
management with the speed of <code>virtual_ptr</code>. Convenience functions
|
||
<code>make_shared_virtual</code> and <code>make_unique_virtual</code> create an object and return a
|
||
smart virtual_ptr to it. Since the exact type of the object is known, the vptr
|
||
is read from a static variable, without incuring the cost of a hash table
|
||
lookup.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here is a variaton of the AST example that uses dynamic allocation and unique
|
||
pointers:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <memory>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
using namespace boost::openmethod::aliases;
|
||
|
||
struct Node {
|
||
virtual ~Node() {}
|
||
};
|
||
|
||
struct Literal : Node {
|
||
Literal(int value) : value(value) {}
|
||
|
||
int value;
|
||
};
|
||
|
||
struct Plus : Node {
|
||
Plus(unique_virtual_ptr<Node> left, unique_virtual_ptr<Node> right)
|
||
: left(std::move(left)), right(std::move(right)) {}
|
||
|
||
unique_virtual_ptr<Node> left, right;
|
||
};
|
||
|
||
struct Negate : Node {
|
||
Negate(unique_virtual_ptr<Node> node) : child(std::move(node)) {}
|
||
|
||
unique_virtual_ptr<Node> child;
|
||
};
|
||
|
||
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
|
||
return node->value;
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Plus> node), int) {
|
||
return value(node->left) + value(node->right);
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
|
||
return -value(node->child);
|
||
}
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
|
||
|
||
auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
|
||
auto expr = make_unique_virtual<Negate>(
|
||
make_unique_virtual<Plus>(
|
||
make_unique_virtual<Literal>(1),
|
||
make_unique_virtual<Literal>(2)));
|
||
|
||
std::cout << value(expr) << "\n"; // -3
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_alternatives_to_virtual_ptr">Alternatives to virtual_ptr</h3>
|
||
<div class="paragraph">
|
||
<p>Virtual arguments can be passed as plain references. In a method declaration,
|
||
parameters with a type decorated with <code>virtual_</code> are considered in overrider
|
||
selection (along with <code>virtual_ptr</code> parameters).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For example, the <code>poke</code> open-method in the Animals example can be rewritten as:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct Animal {
|
||
virtual ~Animal() = default;
|
||
};
|
||
|
||
struct Cat : Animal {};
|
||
|
||
using boost::openmethod::virtual_;
|
||
|
||
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream & os, Cat& /*cat*/), void) {
|
||
os << "hiss";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat);
|
||
|
||
int main() {
|
||
boost::openmethod::initialize();
|
||
|
||
Cat cat;
|
||
poke(std::cout, cat); // hiss
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that <code>virtual_</code> is not used in the overrider. It is also removed from the
|
||
method’s signature.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>By itself, <code>virtual_</code> does not provide any benefits. Passing the virtual
|
||
argument by reference almost compiles to the same code as creating a
|
||
<code>virtual_ptr</code>, using it for one call, then throwing it way. The only difference
|
||
is that the virtual argument is passed as one pointer instead of two.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, we can now customize how the vptr is obtained. When the method sees a
|
||
<code>virtual_</code> parameter, it looks for a <code>boost_openmethod_vptr</code> function that takes
|
||
the parameter (by const reference), and returns a <code>vptr_type</code>. If one is found,
|
||
it is called to obtain the vptr. The vptr for a specific registered class can be
|
||
obtained via a variable template <code>static_vptr</code>, nested in class <code>default_registry</code>
|
||
(more on policies below).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In the following example, we embed a vptr in the object, just like the vptr for
|
||
native virtual functions:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">class Animal {
|
||
protected:
|
||
boost::openmethod::vptr_type vptr;
|
||
friend auto boost_openmethod_vptr(const Animal& a, void*) {
|
||
return a.vptr;
|
||
}
|
||
|
||
public:
|
||
Animal() {
|
||
vptr = boost::openmethod::default_registry::static_vptr<Animal>;
|
||
}
|
||
};
|
||
|
||
class Cat : public Animal {
|
||
public:
|
||
Cat() {
|
||
vptr = boost::openmethod::default_registry::static_vptr<Cat>;
|
||
}
|
||
};
|
||
|
||
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream & os, Cat& /*cat*/), void) {
|
||
os << "hiss\n";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat);
|
||
|
||
int main() {
|
||
boost::openmethod::initialize();
|
||
|
||
Cat cat;
|
||
poke(std::cout, cat); // hiss
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
With this approach, classes need not be polymorphic. A virtual
|
||
destructor might be needed for correct destruction of objects, but it is not
|
||
required by the library.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>inplace_vptr</code> CRTP class automates the creation and management of embedded
|
||
vptrs.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <boost/openmethod/inplace_vptr.hpp>
|
||
|
||
class Animal : public boost::openmethod::inplace_vptr<Animal> {
|
||
};
|
||
|
||
class Cat : public Animal, public boost::openmethod::inplace_vptr<Cat, Animal> {
|
||
};
|
||
|
||
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream & os, Cat& /*cat*/), void) {
|
||
os << "hiss\n";
|
||
}
|
||
|
||
int main() {
|
||
boost::openmethod::initialize();
|
||
|
||
Cat cat;
|
||
poke(std::cout, cat); // hiss
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>inplace_vptr</code> is passed only the class being defined, it adds a vptr to it, and
|
||
defines a <code>boost_openmethod_vptr</code> friend function. If more classes are passed,
|
||
they must be the direct bases of the class potentially involved in open-method
|
||
calls. Its constructor and destructor set the vptr to point to the v-table for
|
||
the class. <code>inplace_vptr</code> also takes care of registering the classes, so this time
|
||
the call to <code>BOOST_OPENMETHOD_CLASSES</code> is not needed.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_core_api">Core API</h3>
|
||
<div class="paragraph">
|
||
<p>OpenMethod provides a macro-free interface: the core API. This is useful in
|
||
certain situations, for example when combining open-methods and templates.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s rewrite the Animals example using the core API. An open-method is
|
||
implemented as an instance of the <code>method</code> template. Its parameters are a
|
||
function signature and a return type:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <boost/openmethod/core.hpp>
|
||
|
||
using namespace boost::openmethod;
|
||
|
||
class poke_openmethod;
|
||
|
||
using poke = method<
|
||
poke_openmethod(std::ostream&, virtual_<Animal&>), void>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>poke_openmethod</code> class acts as the method’s identifier: it separates it
|
||
from other methods with the same signature. The exact name does not really
|
||
matter, and the class needs not be defined, only declared. Inventing a class
|
||
name can get tedious, so OpenMethod provides a macro for that:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <boost/openmethod/macros.hpp>
|
||
|
||
class BOOST_OPENMETHOD_ID(poke);
|
||
|
||
using poke = method<
|
||
BOOST_OPENMETHOD_ID(poke),
|
||
auto(std::ostream&, virtual_ptr<Animal>)->void>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
BOOST_OPENMETHOD and associated macros use <code>BOOST_OPENMETHOD_ID</code> in
|
||
their implementation. This makes it possible to mix the "macro" and "core"
|
||
styles.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We call the method via the nested function object <code>fn</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">poke::fn(std::cout, animal);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Overriders are ordinary functions, added to a method using the nested template
|
||
<code>override</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto poke_cat(std::ostream& os, virtual_ptr<Cat> /*cat*/) {
|
||
os << "hiss";
|
||
}
|
||
|
||
static poke::override<poke_cat> override_poke_cat;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>override</code> can register multiple overriders.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In C++26, we will be able to use <code>_</code> instead of inventing a one-time-use
|
||
identifier. In the meantime, OpenMethod provides a small convenience macro:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <boost/openmethod/macros.hpp>
|
||
|
||
auto poke_dog(std::ostream& os, virtual_ptr<Dog> /*dog*/) {
|
||
os << "bark";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_REGISTER(poke::override<poke_dog>);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>next</code> is available from the method’s nested <code>next</code> template:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto poke_bulldog(std::ostream& os, virtual_ptr<Bulldog> dog) -> void {
|
||
poke::next<poke_bulldog>(os, dog);
|
||
os << " and bite";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_REGISTER(poke::override<poke_bulldog>);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
Since the function uses itself as a template argument in its body, its
|
||
return type cannot be deduced. It must be specified explicitly, either by using
|
||
the old function declaration style or a trailing return type.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Why not call <code>poke_dog</code> directly? We could; however, keep in mind that, in a
|
||
real program, a translation unit is not necessarily aware of the overriders
|
||
added elsewhere - especially in presence of dynamic loading.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We register the classes with <code>use_classes</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_REGISTER(use_classes<Animal, Cat, Dog, Bulldog>);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, we call the method via the static member of the method class <code>fn</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
|
||
std::unique_ptr<Animal> a(new Cat);
|
||
std::unique_ptr<Animal> b(new Dog);
|
||
std::unique_ptr<Animal> c(new Bulldog);
|
||
|
||
poke::fn(std::cout, *a); // prints "hiss"
|
||
std::cout << "\n";
|
||
|
||
poke::fn(std::cout, *b); // prints "bark"
|
||
std::cout << "\n";
|
||
|
||
poke::fn(std::cout, *c); // prints "bark and bite"
|
||
std::cout << "\n";
|
||
|
||
return 0;</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_policies_and_policys">Policies and Facets</h3>
|
||
<div class="paragraph">
|
||
<p>Methods and classes are scoped in a policy. A method can only reference classes
|
||
registered in the same policy. If a class is used as a virtual parameter in
|
||
methods using different policies, it must be registered with each of them.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Class templates <code>use_classes</code>, <code>method</code>, <code>virtual_ptr</code>, and macros
|
||
<code>BOOST_OPENMETHOD</code> and <code>BOOST_OPENMETHOD_CLASSES</code>, accept an additional
|
||
argument, a policy class, which defaults to <code>policies::debug</code> in debug builds,
|
||
and <code>policies::release</code> in release builds.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A policy has a collection of <em>policys</em>. Each policy belongs to a policy category. A
|
||
policy may contain at most one policy of a given category. Facets control how
|
||
type information is obtained, how vptrs are fetched, how errors are handled and
|
||
printed, etc. Some are used in <code>initialize</code> and method dispatch; some are used
|
||
by other policys in the same policy as part of their implementation. See the
|
||
reference for the list of policys. Policies and policys are placed in the
|
||
<code>boost::openmethod::policies</code> namespace. Two stock policies are provided by the
|
||
library: <code>release</code> and <code>debug</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>release</code> policy contains the following policys:</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all stretch">
|
||
<colgroup>
|
||
<col style="width: 33.3333%;">
|
||
<col style="width: 33.3333%;">
|
||
<col style="width: 33.3334%;">
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">policy category</th>
|
||
<th class="tableblock halign-left valign-top">policy</th>
|
||
<th class="tableblock halign-left valign-top">role</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">rtti</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">std_rtti</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">provides type information for classes and objects</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">extern_vptr</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">vptr_vector</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">stores vptrs in an indexed collection</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">type_hash</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">fast_perfect_hash</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">hash type id to an index in a vector</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">error_handler</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">default_error_handler</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">handles errors</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="paragraph">
|
||
<p>The <code>debug</code> policy contains the same policys as <code>release</code>, plus a few more:</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all stretch">
|
||
<colgroup>
|
||
<col style="width: 33.3333%;">
|
||
<col style="width: 33.3333%;">
|
||
<col style="width: 33.3334%;">
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">policy category</th>
|
||
<th class="tableblock halign-left valign-top">policy</th>
|
||
<th class="tableblock halign-left valign-top">role</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">runtime_checks</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">(itself)</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">enables runtime checks</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">output</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">basic_error_output</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">prints error descriptions to <code>stderr</code></p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">trace</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">basic_trace_output</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">enables <code>initialize</code> to print information about dispatch table construction to <code>stderr</code></p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="paragraph">
|
||
<p>Policies, and some policys, have static variables. When it is the case, they are
|
||
implemented as CRTP classes.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Policies can be created from scratch, using the <code>basic_policy</code> template, or
|
||
constructed from existing policies by adding and removing policys. For example,
|
||
<code>policies::debug</code> is a tweak of <code>policies::release</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct debug : release::fork<debug>::with<
|
||
runtime_checks, basic_error_output<debug>,
|
||
basic_trace_output<debug>> {};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>boost::openmethod::default_registry</code> is an alias to <code>release</code> or <code>debug</code>,
|
||
depending on the value of preprocessor symbols <code>NDEBUG</code>. The default policy can
|
||
be overriden by defining the macroprocessor symbol
|
||
<code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> <em>before</em> including
|
||
<code><boost/openmethod/core.hpp></code>. The value of the symbol is used as a default
|
||
template parameter for <code>use_classes</code>, <code>method</code>, <code>virtual_ptr</code>, and others. Once
|
||
the <code>core</code> header has been included, changing <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code>
|
||
has no effect.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_error_handling">Error Handling</h3>
|
||
<div class="paragraph">
|
||
<p>When an error is encountered, the program is terminated by a call to <code>abort</code>. If
|
||
the policy contains an <code>error_handler</code> policy, it provides an <code>error</code> member
|
||
function (or overloaded functions) to be called with an object identifying the
|
||
error. The <code>release</code> and <code>debug</code> policies implement the error policy with
|
||
<code>default_error_handler</code>, which wraps the error object in a variant, and calls a
|
||
handler via a <code>std::function</code>. By default, it prints a description of the error
|
||
to <code>stderr</code> in the <code>debug</code> policy, and does nothing in the <code>release</code> policy. The
|
||
handler can be set with <code>set_error_handler</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
#include <variant>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
struct Animal {
|
||
virtual ~Animal() = default;
|
||
};
|
||
|
||
struct Cat : Animal {};
|
||
struct Dog : Animal {};
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||
|
||
BOOST_OPENMETHOD(trick, (std::ostream&, virtual_ptr<Animal>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
trick, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
|
||
os << "spin\n";
|
||
}
|
||
|
||
auto main() -> int {
|
||
namespace bom = boost::openmethod;
|
||
bom::initialize();
|
||
|
||
bom::default_registry::error_handler::set([](const auto& error) {
|
||
if (std::holds_alternative<bom::not_implemented_error>(error)) {
|
||
throw std::runtime_error("not implemented");
|
||
}
|
||
});
|
||
|
||
Cat felix;
|
||
Dog hector, snoopy;
|
||
std::vector<Animal*> animals = {&hector, &felix, &snoopy};
|
||
|
||
for (auto animal : animals) {
|
||
try {
|
||
trick(std::cout, *animal);
|
||
} catch (std::runtime_error& error) {
|
||
std::cerr << error.what() << "\n";
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Output:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="console">spin
|
||
not implemented
|
||
spin</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can also replace the <code>error_handler</code> policy with our own. For example:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
|
||
#include <boost/openmethod/default_registry.hpp>
|
||
|
||
struct Animal {
|
||
virtual ~Animal() = default;
|
||
};
|
||
|
||
struct Cat : Animal {};
|
||
struct Dog : Animal {};
|
||
|
||
namespace bom = boost::openmethod;
|
||
|
||
struct throw_if_not_implemented : bom::policies::error_handler {
|
||
template<class Registry>
|
||
struct fn {
|
||
static auto error(const bom::openmethod_error&) -> void {
|
||
}
|
||
|
||
static auto error(const bom::not_implemented_error& err) -> void {
|
||
throw err;
|
||
}
|
||
};
|
||
};
|
||
|
||
struct custom_registry : bom::default_registry::with<throw_if_not_implemented> {
|
||
};
|
||
|
||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||
|
||
BOOST_OPENMETHOD(trick, (std::ostream&, virtual_ptr<Animal>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
trick, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
|
||
os << "spin\n";
|
||
}
|
||
|
||
auto main() -> int {
|
||
bom::initialize();
|
||
|
||
Cat felix;
|
||
Dog hector, snoopy;
|
||
std::vector<Animal*> animals = {&hector, &felix, &snoopy};
|
||
|
||
for (auto animal : animals) {
|
||
try {
|
||
trick(std::cout, *animal);
|
||
} catch (bom::not_implemented_error&) {
|
||
std::cout << "not implemented\n";
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="console">spin
|
||
not implemented
|
||
spin</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Stock policy <code>throw_error_handler</code> does this for all the exception types:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct throw_error_handler : error_handler {
|
||
template<class Error>
|
||
[[noreturn]] static auto error(const Error& error) -> void {
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
} // namespace boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_custom_rtti">Custom RTTI</h3>
|
||
<div class="paragraph">
|
||
<p>Stock policies use the <code>std_rtti</code> implementation of <code>rtti</code>. Here is its full
|
||
source:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct std_rtti : rtti {
|
||
template<class Class>
|
||
static constexpr auto is_polymorphic = std::is_polymorphic_v<Class>;
|
||
|
||
template<typename T>
|
||
static type_id static_type() {
|
||
return reinterpret_cast<type_id>(&typeid(T));
|
||
}
|
||
|
||
template<typename T>
|
||
static type_id dynamic_type(const T& obj) {
|
||
return reinterpret_cast<type_id>(&typeid(obj));
|
||
}
|
||
|
||
template<class Stream>
|
||
static void type_name(type_id type, Stream& stream) {
|
||
stream << reinterpret_cast<const std::type_info*>(type)->name();
|
||
}
|
||
|
||
static std::type_index type_index(type_id type) {
|
||
return std::type_index(*reinterpret_cast<const std::type_info*>(type));
|
||
}
|
||
|
||
template<typename D, typename B>
|
||
static D dynamic_cast_ref(B&& obj) {
|
||
return dynamic_cast<D>(obj);
|
||
}
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>is_polymorphic</code> is used to check if a class is polymorphic. This template is
|
||
required.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>static_type</code> is used by class registration, by <code>virtual_ptr</code>'s "final"
|
||
constructs, and to format error and trace messages. <code>T</code> is not restricted to
|
||
the classes that appear as virtual parameters. This function is required.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>dynamic_type</code> is used to locate the v-table for an object. This function is
|
||
usually required. If only the <code>virtual_ptr</code> "final" constructs are used, or
|
||
if <code>boost_openmethod_vptr</code> is provided for all the classes in the policy, it
|
||
can be omitted.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>type_name</code> writes a representation of <code>type</code> to <code>stream</code>. It is used to format
|
||
error and trace messages. <code>Stream</code> is a lighweight version of <code>std::ostream</code>
|
||
with reduced functionality. It only supports insertion of <code>const char*</code>,
|
||
<code>std::string_view</code>, pointers and <code>std::size_t</code>. This function is optional;
|
||
if it is not provided, "type_id(<em>type</em>)" is used.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>type_index</code> returns an object that <em>uniquely</em> identifies a class. Some forms
|
||
of RTTI (most notably, C++'s <code>typeid</code> operator) do not guarantee that the
|
||
type information object for a class is unique within the same program. This
|
||
function is optional; if not provided, <code>type</code> is assumed to be unique, and
|
||
used as is.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>dynamic_cast_ref</code> casts <code>obj</code> to class <code>D</code>. <code>B&&</code> is either a lvalue reference
|
||
(possibly cv-qualified) or a rvalue reference. <code>D</code> has the same reference
|
||
category (and cv-qualifier if applicable) as <code>B</code>. This function is required
|
||
only in presence of virtual inheritance.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Consider a custom RTTI implementation:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct Animal {
|
||
Animal(unsigned type) : type(type) {
|
||
}
|
||
|
||
virtual ~Animal() = default;
|
||
|
||
unsigned type;
|
||
static constexpr unsigned static_type = 1;
|
||
};
|
||
|
||
struct Cat : Animal {
|
||
Cat() : Animal(static_type) {
|
||
}
|
||
|
||
static constexpr unsigned static_type = 2;
|
||
};
|
||
|
||
// ditto for Dog</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This scheme has an interesting property: its type ids are monotonically
|
||
allocated in a small, dense range. Thus, we don’t need to hash them. We can use
|
||
them as indexes in the table of vptrs.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This time we are going to replace the default policy globally. First we need to
|
||
define the custom RTTI policy. We must <em>not</em> include
|
||
<code><boost/openmethod/core.hpp></code> or any header that includes it yet.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here is the policy implementation:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace bom = boost::openmethod;
|
||
|
||
struct custom_rtti : bom::policies::rtti {
|
||
template<class Registry>
|
||
struct fn : bom::policies::rtti::fn<Registry> {
|
||
template<class T>
|
||
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
|
||
|
||
template<typename T>
|
||
static auto static_type() -> bom::type_id {
|
||
if constexpr (is_polymorphic<T>) {
|
||
return reinterpret_cast<bom::type_id>(T::static_type);
|
||
} else {
|
||
return nullptr;
|
||
}
|
||
}
|
||
|
||
template<typename T>
|
||
static auto dynamic_type(const T& obj) -> bom::type_id {
|
||
if constexpr (is_polymorphic<T>) {
|
||
return reinterpret_cast<bom::type_id>(obj.type);
|
||
} else {
|
||
return nullptr;
|
||
}
|
||
}
|
||
};
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This policy is quite minimal. It does not support virtual inheritance. It would
|
||
not produce good error or trace messages, because types would be represented by
|
||
their integer ids.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This time we create a policy from scratch. For that we use the <code>basic_policy</code>
|
||
CRTP template:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct custom_policy : bom::registry<custom_rtti, bom::policies::vptr_vector> {
|
||
};
|
||
|
||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_policy</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Next, we include the main header. Because <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> is
|
||
defined, its value is used for the default policy. Then comes the usual example.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#include <iostream>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
using boost::openmethod::virtual_ptr;
|
||
|
||
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Cat> /*cat*/), void) {
|
||
os << "hiss";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
poke, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
|
||
os << "bark";
|
||
}
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||
|
||
auto main() -> int {
|
||
boost::openmethod::initialize();
|
||
|
||
std::unique_ptr<Animal> a(new Cat);
|
||
std::unique_ptr<Animal> b(new Dog);
|
||
|
||
poke(std::cout, *a); // prints "hiss"
|
||
std::cout << "\n";
|
||
|
||
poke(std::cout, *b); // prints "bark"
|
||
std::cout << "\n";
|
||
|
||
return 0;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This programs works even if standard RTTI is disabled.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_deferred_rtti">Deferred RTTI</h3>
|
||
<div class="paragraph">
|
||
<p>In the previous example, the RTTI system assigns types id statically. It is more
|
||
common to allocate them using a global counter, manipulated by static
|
||
constructors. This is a problem, because <code>static_type</code> is used by class
|
||
registration. It may read the custom type ids <em>before</em> they are have been
|
||
initialized.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The solution is to add the <code>deferred_static_rtti</code> policy to the policy; it defers
|
||
reading the type information until <code>initialize</code> is called.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This time let’s support virtual inheritance as well. First the domain classes:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct custom_type_info {
|
||
static unsigned last;
|
||
unsigned id = ++last;
|
||
};
|
||
|
||
unsigned custom_type_info::last;
|
||
|
||
struct Animal {
|
||
Animal() {
|
||
type = type_info.id;
|
||
}
|
||
|
||
virtual ~Animal() = default;
|
||
|
||
virtual auto cast_impl(unsigned target) -> void* {
|
||
if (type_info.id == target) {
|
||
return this;
|
||
} else {
|
||
return nullptr;
|
||
}
|
||
}
|
||
|
||
template<class Class>
|
||
auto cast() -> Class* {
|
||
return reinterpret_cast<Class*>(cast_impl(Class::type_info.id));
|
||
}
|
||
|
||
static custom_type_info type_info;
|
||
unsigned type;
|
||
};
|
||
|
||
custom_type_info Animal::type_info;
|
||
|
||
struct Cat : virtual Animal {
|
||
Cat() {
|
||
type = type_info.id;
|
||
}
|
||
|
||
virtual auto cast_impl(unsigned target) -> void* {
|
||
if (type_info.id == target) {
|
||
return this;
|
||
} else {
|
||
return Animal::cast_impl(target);
|
||
}
|
||
}
|
||
|
||
static custom_type_info type_info;
|
||
};
|
||
|
||
custom_type_info Cat::type_info;
|
||
// ditto for Dog</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The rtti policy is the same, with one more function:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct custom_rtti : bom::policies::rtti {
|
||
// as before
|
||
|
||
// to support virtual inheritance:
|
||
template<typename Derived, typename Base>
|
||
static auto dynamic_cast_ref(Base&& obj) -> Derived {
|
||
using base_type = std::remove_reference_t<Base>;
|
||
if constexpr (std::is_base_of_v<Animal, base_type>) {
|
||
return *obj.template cast<std::remove_reference_t<Derived>>();
|
||
} else {
|
||
abort(); // not supported
|
||
}
|
||
}
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, the policy contains an additional policy - <code>deferred_static_rtti</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct custom_policy
|
||
: bom::policies::basic_policy<
|
||
custom_policy, custom_rtti,
|
||
bom::policies::deferred_static_rtti, // <-- additional policy
|
||
bom::policies::vptr_vector<custom_policy>> {};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The example is the same as in the previous section.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="tutorials_dynamic_loading">Dynamic Loading</h3>
|
||
<div class="paragraph">
|
||
<p>OpenMethod supports dynamic loading on operating systems that are capable of
|
||
handling C++ templates correctly during dynamic link. A dynamic library can add
|
||
classes, methods and overriders to an existing policy. <code>initialize</code> must then be
|
||
called to rebuild the dispatch tables.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This leads to a problem: any <code>virtual_ptr</code> in existence before <code>initialize</code> is
|
||
called again becomes invalid. This also applies to vptrs that are stored inside
|
||
objects by <code>inplace_vptr</code>.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
This applies only to cases where a dynamic library adds to an <em>existing</em>
|
||
policy. Even if the dynamic library itself uses open-methods, for example as an
|
||
implementation detail, but it uses its own policy, there is no issue.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The solution is to use a policy that contains the <code>indirect_vptr</code> policy. Instead
|
||
of storing the vptr directly, it stores a reference to the vptr.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here is an example:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// dl.hpp
|
||
|
||
#include <string>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
|
||
struct Animal {
|
||
virtual ~Animal() {
|
||
}
|
||
};
|
||
|
||
struct Herbivore : Animal {};
|
||
struct Carnivore : Animal {};
|
||
struct Cow : Herbivore {};
|
||
struct Wolf : Carnivore {};
|
||
|
||
struct dynamic : boost::openmethod::default_registry::with<
|
||
boost::openmethod::policies::indirect_vptr> {};
|
||
|
||
template<class Class>
|
||
using dyn_vptr = boost::openmethod::virtual_ptr<Class, dynamic>;
|
||
|
||
BOOST_OPENMETHOD(
|
||
encounter, (dyn_vptr<Animal>, dyn_vptr<Animal>), std::string,
|
||
dynamic);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
The policy must be passed to the method as well as the
|
||
<code>virtual_ptr</code>s.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>indirect_vptr</code> policy tells <code>virtual_ptr</code> to use a pointer to the vptr. Even
|
||
tough the value of the vptr changes when <code>initialize</code> is called, the vptrs are
|
||
stored in the same place (the policy’s <code>static_vptr<Class></code> variables).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can now register the classes and and provide an overrider:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// dl_main.cpp
|
||
|
||
#include <cstring>
|
||
#include <iostream>
|
||
#include <dlfcn.h>
|
||
#include <unistd.h>
|
||
|
||
#include <boost/openmethod.hpp>
|
||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||
#include <boost/openmethod/compiler.hpp>
|
||
|
||
#include "dl.hpp"
|
||
|
||
BOOST_OPENMETHOD_CLASSES(
|
||
Animal, Herbivore, Cow, Wolf, Carnivore, dynamic);
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter, (dyn_vptr<Animal>, dyn_vptr<Animal>), std::string) {
|
||
return "ignore\n";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>At this point we only have one overrider. Animals of all species ignore one
|
||
another:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto main() -> int {
|
||
using namespace boost::openmethod;
|
||
|
||
initialize<dynamic>();
|
||
|
||
std::cout << "Before loading library\n";
|
||
|
||
auto gracie = make_unique_virtual<Cow, dynamic>();
|
||
// Wolf _willy;
|
||
// auto willy = virtual_ptr<Wolf, dynamic>(_willy);
|
||
auto willy = make_unique_virtual<Wolf, dynamic>();
|
||
|
||
std::cout << "Gracie encounters Willy -> "
|
||
<< encounter(gracie, willy); // ignore
|
||
std::cout << "Willy encounters Gracie -> "
|
||
<< encounter(willy, gracie); // ignore</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s load a dynamic library containing this code:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">// dl_shared.cpp
|
||
|
||
#include <string>
|
||
#include <boost/openmethod.hpp>
|
||
|
||
#include "dl.hpp"
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter, (dyn_vptr<Herbivore>, dyn_vptr<Carnivore>), std::string) {
|
||
return "run\n";
|
||
}
|
||
|
||
struct Tiger : Carnivore {};
|
||
|
||
BOOST_OPENMETHOD_CLASSES(Tiger, Carnivore, dynamic);
|
||
|
||
extern "C" auto make_tiger() -> Tiger* {
|
||
return new Tiger;
|
||
}
|
||
|
||
BOOST_OPENMETHOD_OVERRIDE(
|
||
encounter, (dyn_vptr<Carnivore>, dyn_vptr<Herbivore>), std::string) {
|
||
return "hunt\n";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now back to <code>main</code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++"> char dl_path[4096];
|
||
dl_path[readlink("/proc/self/exe", dl_path, sizeof(dl_path))] = 0;
|
||
*strrchr(dl_path, '/') = 0;
|
||
strcat(dl_path, "/libdl_shared.so");
|
||
void* handle = dlopen(dl_path, RTLD_NOW);
|
||
|
||
if (!handle) {
|
||
std::cerr << "dlopen() failed: " << dlerror() << "\n";
|
||
exit(1);
|
||
}
|
||
|
||
std::cout << "\nAfter loading library\n";
|
||
|
||
boost::openmethod::initialize<dynamic>();
|
||
|
||
auto make_tiger =
|
||
reinterpret_cast<Animal* (*)()>(dlsym(handle, "make_tiger"));
|
||
|
||
if (!make_tiger) {
|
||
std::cerr << "dlsym() failed: " << dlerror() << "\n";
|
||
exit(1);
|
||
}
|
||
|
||
std::cout << "Willy encounters Gracie -> "
|
||
<< encounter(willy, gracie); // hunt
|
||
|
||
{
|
||
auto hobbes = std::unique_ptr<Animal>(make_tiger());
|
||
std::cout << "Gracie encounters Hobbes -> "
|
||
<< encounter(gracie, *hobbes); // run
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>After unloading the library, we must call <code>initialize</code> again:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++"> dlclose(handle);
|
||
|
||
std::cout << "\nAfter unloading library\n";
|
||
|
||
boost::openmethod::initialize<dynamic>();
|
||
|
||
std::cout << "Gracie encounters Willy -> "
|
||
<< encounter(gracie, willy); // ignore
|
||
std::cout << "Willy encounters Gracie -> "
|
||
<< encounter(willy, gracie); // ignore</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="tutorials_reference">Reference</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="ref_overview">Overview</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_requirements">Requirements</h4>
|
||
<div class="paragraph">
|
||
<p>OpenMethod requires C++17 or above. It depends on the following Boost libraries:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>Assert</p>
|
||
</li>
|
||
<li>
|
||
<p>Config</p>
|
||
</li>
|
||
<li>
|
||
<p>Core</p>
|
||
</li>
|
||
<li>
|
||
<p>DynamicBitset</p>
|
||
</li>
|
||
<li>
|
||
<p>Mp11</p>
|
||
</li>
|
||
<li>
|
||
<p>Preprocessor</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Boost.Test is also required to build and run the unit tests.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_installation">Installation</h4>
|
||
<div class="paragraph">
|
||
<p>The library is headers-only. You can install it system-wide, or add the path to
|
||
the <code>include</code> directory to your project’s include path.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_namespaces">Namespaces</h4>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethod">boost::openmethod</h5>
|
||
<div class="paragraph">
|
||
<p>The library’s main namespace. Contains <code>method</code>, <code>virtual_ptr</code> and
|
||
<code>virtual_ptr_traits</code>, <code>use_classes</code>, the <code>default_registry</code>, etc.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpolicies">boost::openmethod::policies</h5>
|
||
<div class="paragraph">
|
||
<p>Contains the policy framework.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_headers">Headers</h4>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodcore_hpp"><boost/openmethod/core.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>The library’s main header. Provides <code>method</code>, <code>virtual_ptr</code> and
|
||
<code>virtual_ptr_traits</code>, <code>use_classes</code>, the default policy, etc.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> is defined before including this header,
|
||
its value is used as the default value for the <code>Policy</code> template parameter
|
||
throughout the code. Otherwise, <code>boost::openmethod::default_registry</code> is used.
|
||
Setting <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> after including the core header has no
|
||
effect.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodmacros_hpp"><boost/openmethod/macros.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides <code>BOOST_REGISTER_CLASSES</code>, <code>BOOST_OPENMETHOD</code>,
|
||
<code>BOOST_OPENMETHOD_OVERRIDE</code> and other macros.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethod_hpp"><boost/openmethod.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Convenience header. Includes <code><boost/openmethod/core.hpp></code> and
|
||
<code><boost/openmethod/macros.hpp></code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Also imports <code>boost::openmethod::virtual_ptr</code> in the global namespace. This is
|
||
usually regarded as bad practice. The rationale is that OpenMethod emulates a
|
||
language feature, and <code>virtual_ptr</code> is equivalent to keyword, similar to
|
||
<code>virtual</code>. Besides, the macros are global as well.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>There are two ways to avoid importing <code>virtual_ptr</code> while still using the
|
||
macros:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>Define <code>BOOST_OPENMETHOD_NO_GLOBAL_VIRTUAL_PTR</code> before including
|
||
<code><boost/openmethod.hpp></code>. This disables the import of <code>virtual_ptr</code> in the
|
||
global namespace.</p>
|
||
</li>
|
||
<li>
|
||
<p>Include <code><boost/openmethod/core.hpp>`and `<boost/openmethod/macros.hpp></code>.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodcompiler_hpp"><boost/openmethod/compiler.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides <code>intialize</code> and <code>finalize</code>. Typically included only by the translation
|
||
unit that contains <code>main</code>, unless dynamic loading is used in other places in the
|
||
program.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodshared_ptr_hpp"><boost/openmethod/interop/std_shared_ptr.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides support for using <code>std::shared_ptr</code> in place of plain pointers in
|
||
virtual parameters.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodunique_hpp"><boost/openmethod/unique_.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides support for using <code>std::unique_ptr</code> in place of plain pointers in
|
||
virtual parameters.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodinplace_vptr_hpp"><boost/openmethod/inplace_vptr.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides support for storing v-table pointers directly in objects, in the same
|
||
manner as native virtual functions.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpolicies_hpp"><boost/openmethod/policies.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides the <code>debug</code> and <code>release</code> policies in the <code>boost::openmethod::policies</code>
|
||
namespace, and <code>default_registry</code> in the <code>boost::openmethod</code> namespace, which is
|
||
an alias to either <code>debug</code> or <code>release</code>, depending on the value of the
|
||
preprocessor symbol <code>NDEBUG</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Usually not included directly. Can be used to create custom policies from stock
|
||
policies, by forking them and adjusting a few policys.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesbasic_policy_hpp"><boost/openmethod/policies/basic_policy.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Provides the constructs used in the policy framework, essentially
|
||
<code>basic_policy</code>, <code>policy</code>, and its abstract subclasses (<code>rtti</code>, <code>extern_vptr</code>,
|
||
etc).</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesstd_rtti_hpp"><boost/openmethod/policies/std_rtti.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>rtti</code> policy using standard RTTI.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesminimal_rtti_hpp"><boost/openmethod/policies/minimal_rtti.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>rtti</code> policy using a minimal RTTI implementation. Can be used only with the "final" constructs, or with intrusive v-table pointers.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesvptr_vector_hpp"><boost/openmethod/policies/vptr_vector.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>extern_vptr</code> policy using a vector of pointers.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesvptr_map_hpp"><boost/openmethod/policies/vptr_map.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>extern_vptr</code> policy using a map of pointers.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesfast_perfect_hash_hpp"><boost/openmethod/policies/fast_perfect_hash.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>type_hash</code> policy using a perfect hash function.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesdefault_error_handler_hpp"><boost/openmethod/policies/default_error_handler.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>error_handler</code> policy by routing the error through a
|
||
<code>std::function</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesthrow_error_handler_hpp"><boost/openmethod/policies/throw_error_handler.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>error_handler</code> policy by throwing an exception.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesbasic_error_output_hpp"><boost/openmethod/policies/basic_error_output.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>output</code> policy using a lightweight version of
|
||
<code>std::ostream</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_boostopenmethodpoliciesbasic_trace_output_hpp"><boost/openmethod/policies/basic_trace_output.hpp></h5>
|
||
<div class="paragraph">
|
||
<p>Implements the <code>trace</code> policy using a lightweight version of
|
||
<code>std::ostream</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD">BOOST_OPENMETHOD</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD(NAME, (PARAMETERS...), RETURN_TYPE [, POLICY]);</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Declares a method.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The macro expands to several constructs:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>A <code>struct</code> forward declaration that acts as the method’s identifier:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct BOOST_OPENMETHOD_ID(NAME);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>An inline function template, constrained to take the same <code>PARAMETERS</code>,
|
||
without the <code>virtual_</code> decorators, returning a <code>RETURN_TYPE</code>. The function
|
||
forwards to<br>
|
||
<code>method<BOOST_OPENMETHOD_ID(NAME)(PARAMETERS…​), RETURN_TYPE, POLICY>::fn</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>A guide function used to match overriders with the method:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto BOOST_OPENMETHOD_ID(NAME)_guide(...)
|
||
-> ::boost::openmethod::method<
|
||
BOOST_OPENMETHOD_ID(NAME)(PARAMETERS...), RETURN_TYPE [, POLICY]>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>NAME</code> must be an <strong>identifier</strong>. Qualified names are not allowed.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
The default value for <code>POLICY</code> is the value of
|
||
<code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> at the point <code><boost/openmethod/core.hpp></code> is
|
||
included. Changing the value of this symbol has no effect after that point.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_OVERRIDE">BOOST_OPENMETHOD_OVERRIDE</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_2">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
|
||
// body
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_2">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_OVERRIDE</code> adds an overrider to a method.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The method is deduced from a call to a method guide function with the
|
||
overrider’s arguments.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The macro creates several entities in the current scope.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>A class template that acts as a container for the overriders of the methods
|
||
called <code>NAME</code>:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename...> BOOST_OPENMETHOD_OVERRIDERS(NAME);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>A specialization of the container template for the overrider:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)> {
|
||
static auto fn(PARAMETERS...) -> RETURN_TYPE;
|
||
static auto has_next() -> bool;
|
||
template<typename... Args>
|
||
static auto next(typename... Args) -> RETURN_TYPE;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>where:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>fn</code> is the overrider function.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>has_next()</code> returns <code>true</code> if a less specialized overrider exists.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>next(Args…​ args)</code> calls the next most specialized overrider via the
|
||
pointer stored in the method’s <code>next<fn></code> member variable.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, the macro starts the definition of the overrider function:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)>::fn(
|
||
PARAMETERS...) -> RETURN_TYPE</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The block following the call to the macro is the body of the function.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>NAME</code> must be an <strong>identifier</strong>. Qualified names are not allowed.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_INLINE_OVERRIDE">BOOST_OPENMETHOD_INLINE_OVERRIDE</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_3">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_INLINE_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
|
||
// body
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_3">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_INLINE_OVERRIDE</code> performs the same function as
|
||
<code>BOOST_OPENMETHOD_OVERRIDE</code>, except that the overrider is defined inline.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>NAME</code> must be an <strong>identifier</strong>. Qualified names are not allowed.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_boost_openmethod_declare_overrider">BOOST_OPENMETHOD_DECLARE_OVERRIDER</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_4">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_4">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Declares an overrider for a method.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The method is deduced from a call to a method guide function with the
|
||
overrider’s arguments.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The macro creates several entities in the current scope.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>A class template that acts as a container for the overriders of the methods
|
||
called <code>NAME</code>:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename...> BOOST_OPENMETHOD_OVERRIDERS(NAME);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>A specialization of the container template for the overrider:</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)> {
|
||
static auto fn(PARAMETERS...) -> RETURN_TYPE;
|
||
static auto has_next() -> bool;
|
||
template<typename... Args>
|
||
static auto next(typename... Args) -> RETURN_TYPE;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>where:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>fn</code> is the overrider function.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>has_next()</code> returns <code>true</code> if a less specialized overrider exists.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>next(Args…​ args)</code> calls the next most specialized overrider via the
|
||
pointer stored in the method’s <code>next<fn></code> member variable.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_DECLARE_OVERRIDER</code> can be called in a header file, with a
|
||
semicolon after the call. It can be called in a header file, but not multiple
|
||
times in the same translation unit.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>NAME</code> must be an <strong>identifier</strong>. Qualified names are not allowed.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_boost_openmethod_define_overrider">BOOST_OPENMETHOD_DEFINE_OVERRIDER</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_5">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_5">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Defines the body of an overrider declared with
|
||
<code>BOOST_OPENMETHOD_DECLARE_OVERRIDER</code>. It should be called in an implementation
|
||
file, and followed by a function body.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>NAME</code> must be an <strong>identifier</strong>. Qualified names are not allowed.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_boost_openmethod_overrider">BOOST_OPENMETHOD_OVERRIDER</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_6">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_6">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Expands to the specialization of the class template that contains the overrider
|
||
for with the given name, parameter list and return type.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_ID">BOOST_OPENMETHOD_ID</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_7">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_ID(NAME) /* unspecified */</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_7">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Generates a long, obfuscated name from a short name. All the other names
|
||
generated by macros are based on this name.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_boost_openmethod_guide">BOOST_OPENMETHOD_GUIDE</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_8">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_GUIDE(NAME) /* unspecified */</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_8">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Expands to the name of the guide function used to match overriders to methods.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_boost_openmethod_overriders">BOOST_OPENMETHOD_OVERRIDERS</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_9">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">#define BOOST_OPENMETHOD_OVERRIDERS(NAME) \
|
||
BOOST_PP_CAT(BOOST_OPENMETHOD_ID(NAME), _overriders)</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_9">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_OVERRIDERS</code> expands to the name of the class template that
|
||
contains the overriders for all the methods with a given name.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_REGISTER">BOOST_OPENMETHOD_REGISTER</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_10">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_REGISTER(TYPE);</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_10">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Creates a static instance of <code>TYPE</code>, using a unique generated name.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_CLASSES">BOOST_OPENMETHOD_CLASSES</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_11">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/macros.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">BOOST_OPENMETHOD_CLASSES(CLASSES...[, POLICY]);</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_11">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Register <code>CLASSES</code> in POLICY.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
The default value for <code>POLICY</code> is the value of
|
||
<code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> when <code><boost/openmethod/core.hpp></code> is
|
||
included. Subsequently changing it has no retroactive effect.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This macro is a wrapper around <code>use_classes</code>; see its documentation for more
|
||
details.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="BOOST_OPENMETHOD_DEFAULT_REGISTRY">BOOST_OPENMETHOD_DEFAULT_REGISTRY</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_12">Description</h4>
|
||
<div class="paragraph">
|
||
<p>The name of the default policy.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> is the default value for the <code>Policy</code> template
|
||
parameter of <code>method</code>, <code>use_classes</code>, and other constructs defined in
|
||
<code><boost/openmethod/core.hpp></code>. If it is not defined,
|
||
<code>::boost::openmethod::policy::default_registry</code> is used.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> can be defined by a program to change the
|
||
default policy globally. Once <code><boost/openmethod/core.hpp></code> has been included,
|
||
redefining the symbol has no effect. To override the default policy, proceed as
|
||
follows:</p>
|
||
</div>
|
||
<div class="olist arabic">
|
||
<ol class="arabic">
|
||
<li>
|
||
<p>Include headers under <code>boost/openmethod/policies/</code> as needed.</p>
|
||
</li>
|
||
<li>
|
||
<p>Create a policy class, and set <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Include <code><boost/openmethod/core.hpp></code>.</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_initialize">initialize</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_12">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/compiler.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
auto initialize() -> /*unspecified*/;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_13">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Initializes dispatch data for the methods registered in <code>Policy</code>. This function
|
||
must be called before any calls to those methods, and after loading or unloading
|
||
a dynamic library that adds classes, methods or overriders to <code>Policy</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The return value is an object that contains a member variable, <code>report</code>, that
|
||
contains the following information:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>std::size_t cells</code>: the number of cells used by the v-tables and the multiple
|
||
dispatch tables.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>std::size_t not_implemented</code>: the number of methods that don’t have an
|
||
overrider for at least one combination of virtual arguments.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>std::size_t ambiguous</code>: the number of methods that have more than one
|
||
overrider, none of which is more specific than the others, for at least one
|
||
combination of virtual arguments.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_finalize">finalize</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_13">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/compiler.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
auto finalize() -> void;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_14">Description</h4>
|
||
<div class="paragraph">
|
||
<p>De-allocates the resources allocated by <code>initialize</code> for the <code>Policy</code>, including
|
||
resources allocated by the policys in <code>Policy</code>. Resources are de-allocated in an
|
||
arbitrary order. It is not necessary to call <code>finalize</code> between calls to
|
||
<code>initialize</code>. It is provided mainly for the benefit of memory leak detection
|
||
schemes.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_type_id">type_id</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_14">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/policies/basic_policy.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
using type_id = std::uintptr_t;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_15">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>type_id</code> is an unsigned integer type used to identify types. It is wide enough
|
||
to contain a pointer.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_vptr_type">vptr_type</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_15">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/policies/basic_policy.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
using vptr_type = const /*unspecified*/ *;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_16">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>vptr_type</code> is the type of a pointer to a v-table.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="ref_method">method</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_16">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<
|
||
typename Method, typename ReturnType,
|
||
class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
class method;
|
||
|
||
template<typename Name, typename... Parameters, typename ReturnType, class Policy>
|
||
class method<Name(Parameters...), ReturnType, Policy> {
|
||
public:
|
||
using function_type = ReturnType (*)(CallParameters...);
|
||
|
||
auto operator()(CallParameters... args) const -> ReturnType;
|
||
|
||
static method fn;
|
||
|
||
template<auto... Functions>
|
||
struct override;
|
||
|
||
template<auto Overrider>
|
||
static function_type next;
|
||
|
||
private:
|
||
method();
|
||
method(const method&) = delete;
|
||
method(method&&) = delete;
|
||
~method();
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_17">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>method</code> implements an open-method that takes a parameter list - <code>Parameters</code> -
|
||
and returns a <code>ReturnType</code>. <code>Name</code> can be any type. Its purpose is to make it
|
||
possible to have multiple methods with the same signature. Typically, <code>Name</code> is
|
||
a class whose name reflects the method’s purpose.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>Parameters</code> must contain at least one virtual parameter, i.e. a parameter that
|
||
has a type in the form <code>virtual_ptr<T, Policy></code> or <code>virtual_<T></code>. The
|
||
dynamic types of the virtual arguments (the arguments corresponding to virtual
|
||
parameters in the method’s signature) are taken into account to select the
|
||
overrider to call.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A <code>method</code> is attached to a <code>Policy</code>, which influences several parts of the
|
||
dispatch mechanism - for example, how to obtain a v-table pointer for an object,
|
||
how to report errors, whether to perform sanity checks, etc.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_members">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="ref_constructor">constructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">method();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Add the method to the list of methods registered in <code>Policy</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The constructor is private. The only instance is the static member variable
|
||
<code>fn</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_destructor">destructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">~method();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Remove the method from the list of methods registered in <code>Policy</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_operator">operator()</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto operator()(CallParameters... args) const -> ReturnType;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Call the method with the arguments <code>args</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>CallParameters</code> are the <code>Parameters</code> without the <code>virtual_</code> decorators. Note
|
||
that <code>virtual_ptr</code>s are preserved.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The overrider is selected in a process similar to overloaded function
|
||
resolution, with extra rules to handle ambiguities. It proceeds as follows:</p>
|
||
</div>
|
||
<div class="olist arabic">
|
||
<ol class="arabic">
|
||
<li>
|
||
<p>Form the set of all applicable overriders. An overrider is applicable if it
|
||
can be called with the arguments passed to the method.</p>
|
||
</li>
|
||
<li>
|
||
<p>If the set is empty, call the error handler (if present in the policy), then
|
||
terminate the program with <code>abort</code></p>
|
||
</li>
|
||
<li>
|
||
<p>Remove the overriders that are dominated by other overriders in the set.
|
||
Overrider A dominates overrider B if any of its virtual formal parameters is
|
||
more specialized than B’s, and if none of B’s virtual parameters is more
|
||
specialized than A’s.</p>
|
||
</li>
|
||
<li>
|
||
<p>If the resulting set contains only one overrider, call it.</p>
|
||
</li>
|
||
<li>
|
||
<p>If the return type is a registered polymorphic type, remove all the
|
||
overriders that return a less specific type than the others.</p>
|
||
</li>
|
||
<li>
|
||
<p>If the resulting set contains only one overrider, call it.</p>
|
||
</li>
|
||
<li>
|
||
<p>Otherwise, call one of the remaining overriders. Which overrider is selected
|
||
is not specified, but it is the same across calls with the same arguments
|
||
types.</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For each virtual argument <code>arg</code>, the dispatch mechanism calls
|
||
<code>virtual_traits::peek(arg)</code> and deduces the v-table pointer from the <code>result</code>,
|
||
using the first of the following methods that applies:</p>
|
||
</div>
|
||
<div class="olist arabic">
|
||
<ol class="arabic">
|
||
<li>
|
||
<p>If <code>result</code> is a <code>virtual_ptr</code>, get the pointer to the v-table from it.</p>
|
||
</li>
|
||
<li>
|
||
<p>If a function named <code>boost_openmethod_vptr</code> that takes <code>result</code> and returns a
|
||
<code>vptr_type</code> exists, call it.</p>
|
||
</li>
|
||
<li>
|
||
<p>Call <code>Policy::dynamic_vptr(result)</code>.</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_fn">fn</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static method fn;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>method</code>'s unique instance. The method is called via the call
|
||
operator on <code>fn</code>: <code>method::fn(args…​)</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_override">override</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<auto... Functions>
|
||
struct override;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Add <em>Functions</em> to the overriders of <code>method</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_next">next</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<auto Overrider>
|
||
static function_type next;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Pointer to the next most specialized overrider after <em>Overrider</em>, i.e. the
|
||
overrider that would be called for the same tuple of virtual arguments if
|
||
<em>Overrider</em> was not present. Set to <code>nullptr</code> if no such overrider exists.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="method_override">method::override</h3>
|
||
<div class="sect3">
|
||
<h4 id="ref_synopsis_17">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<typename Signature, typename ReturnType, class Policy>
|
||
template<auto... Functions>
|
||
struct method<Signature, ReturnType, Policy>::override {
|
||
override();
|
||
~override();
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Usage:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">method<Signature, ReturnType, Policy>::override<Functions...> some_unique_name;
|
||
// at file scope</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_description_18">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>override</code>, instantiated as a static object, add one or more overriders to an
|
||
open-method.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><em>Functions</em> must fulfill the following requirements:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>Have the same number of formal parameters as the method.</p>
|
||
</li>
|
||
<li>
|
||
<p>Each parameter in the same position as a <code>virtual_ptr<T></code> in the method’s
|
||
parameter list must be a <code>virtual_ptr<U></code>, where <em>U</em> is covariant with <em>T</em>. The
|
||
<em>Policy</em> of the <code>virtual_ptr</code>s must be the same as the method’s <em>Policy</em>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Each formal parameter in the same position as a <code>virtual_</code> parameter must have
|
||
a type that is covariant with the type of the method’s parameter.</p>
|
||
</li>
|
||
<li>
|
||
<p>All other formal parameters must have the same type as the method’s
|
||
corresponding parameters.</p>
|
||
</li>
|
||
<li>
|
||
<p>The return type of the overrider must be the same as the method’s return type
|
||
or, if it is a polymorphic type, covariant with the method’s return type.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="ref_members_2">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="ref_constructor_2">constructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">override<Functions>::override();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Add <em>Functions</em> to the overriders of <code>method</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="ref_destructor_2">Destructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">override<Functions>::~method();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Remove <em>Functions</em> from the overriders of <code>method</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr">virtual_ptr</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p><code>virtual_ptr</code> is defined in <code><boost/openmethod/core.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
class virtual_ptr {
|
||
public:
|
||
static constexpr bool is_smart_ptr = /* see below */;
|
||
using element_type = /* see below */;
|
||
|
||
virtual_ptr();
|
||
virtual_ptr(nullptr_t);
|
||
template<class Other> virtual_ptr(Other& other);
|
||
template<class Other> virtual_ptr(const Other& other);
|
||
template<class Other> virtual_ptr(Other&& other);
|
||
|
||
virtual_ptr& operator =(nullptr_t);
|
||
template<class Other> virtual_ptr& operator =(Other& other);
|
||
template<class Other> virtual_ptr& operator =(const Other& other);
|
||
template<class Other> virtual_ptr& operator =(Other&& other);
|
||
|
||
template<class Other>
|
||
static auto final(Other&& obj);
|
||
|
||
auto get() const -> element_type*;
|
||
auto operator->() const -> element_type*;
|
||
auto operator*() const -> element_type&;
|
||
auto pointer() const -> const Class*&;
|
||
|
||
template<typename Other>
|
||
auto cast() const -> virtual_ptr<Other, Policy>;
|
||
};
|
||
|
||
template<class Class>
|
||
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||
|
||
template<class Class>
|
||
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<
|
||
Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||
|
||
template<class Policy, class Class>
|
||
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<Class, Policy>;
|
||
|
||
template<class Left, class Right, class Policy>
|
||
auto operator==(
|
||
const virtual_ptr<Left, Policy>& left,
|
||
const virtual_ptr<Right, Policy>& right) -> bool;
|
||
|
||
template<class Left, class Right, class Policy>
|
||
auto operator!=(
|
||
const virtual_ptr<Left, Policy>& left,
|
||
const virtual_ptr<Right, Policy>& right) -> bool;
|
||
|
||
} // namespace boost::openmethod</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/interop/std_shared_ptr.hpp></code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
using shared_virtual_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;
|
||
|
||
template<
|
||
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY, typename... T>
|
||
inline auto make_shared_virtual(T&&... args)
|
||
-> shared_virtual_ptr<Class, Policy>;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/interop/std_unique_ptr.hpp></code>:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
using unique_virtual_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;
|
||
|
||
template<
|
||
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY, typename... T>
|
||
inline auto make_unique_virtual(T&&... args)
|
||
-> unique_virtual_ptr<Class, Policy>;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>virtual_ptr</code> is a wide pointer that combines a pointer to an object and a
|
||
pointer to its v-table. The object pointer can be a plain pointer or a smart
|
||
pointer. Specializations of <code>virtual_traits</code> are required for smart pointers.
|
||
They are provided for <code>std::unique_ptr</code> and <code>std::shared_ptr</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A plain <code>virtual_ptr</code> can be constructed from a reference, a smart pointer, or
|
||
another <code>virtual_ptr</code>. A smart <code>virtual_ptr</code> can be constructed from a smart
|
||
pointer or from a smart <code>virtual_ptr</code>. Usual conversions - from derived to base,
|
||
and from non-const to const - are supported.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_is_smart_ptr">is_smart_ptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static constexpr bool is_smart_ptr;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>true</code> if <code>Class</code> is a smart pointer, <code>false</code> otherwise. The value is derived
|
||
from <code>virtual_traits<Class, Policy></code>: if it has a member template called
|
||
<code>rebind</code>, <code>Class</code> is considered a smart pointer.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_element_type">element_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">using element_type = std::conditional_t<
|
||
is_smart_ptr, typename Class::element_type, Class>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The class of the object pointed to.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_constructors">constructors</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">virtual_ptr(); // 1
|
||
virtual_ptr(nullptr_t); // 2
|
||
template<class Other> virtual_ptr(Other& other); // 3
|
||
template<class Other> virtual_ptr(const Other& other); // 4
|
||
template<class Other> virtual_ptr(Other&& other); // 5
|
||
template<class Other> virtual_ptr(Other* other); // 6</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(1) Default constructor. Sets the v-table pointer to <code>nullptr</code>. If <code>Class</code> is
|
||
<em>not</em> a smart pointer, the value of object pointer is is undefined.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(2) Sets both the object and v-table pointers to <code>nullptr</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(3), (4) For plain <code>virtual_ptr</code>s, <code>other</code> must be either a lvalue
|
||
reference to an object of a registered class, or a <code>virtual_ptr</code> (plain or
|
||
smart). For smart <code>virtual_ptr</code>s, <code>other</code> must be a reference to a smart
|
||
pointer, or a reference to a smart <code>virtual_ptr</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(5) Constructs a <code>virtual_ptr</code> from a smart pointer or a smart <code>virtual_ptr</code>.
|
||
The object pointer is moved from <code>other</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(6) Constructs a <code>virtual_ptr</code> from a plain pointer. Available only for plain
|
||
<code>virtual_ptr</code>s.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>other</code> is also a <code>virtual_ptr</code>, the v-table pointer is copied from it.
|
||
Otherwise, it is deduced from the object. The <code>Policy</code> must be the same for both
|
||
<code>virtual_ptr</code>s.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_assignment_operators">assignment operators</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">virtual_ptr& operator =(nullptr_t); // 1
|
||
template<class Other> virtual_ptr& operator =(Other& other); // 2
|
||
template<class Other> virtual_ptr& operator =(const Other& other); // 3
|
||
template<class Other> virtual_ptr& operator =(Other&& other); // 4
|
||
template<class Other> virtual_ptr& operator =(Other* other); // 5</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(1) Sets both the object and v-table pointers to <code>nullptr</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(2), (3) For plain <code>virtual_ptr</code>s, <code>other</code> must be either a lvalue
|
||
reference to an object of a registered class, or a <code>virtual_ptr</code> (plain or
|
||
smart). For smart <code>virtual_ptr</code>s, <code>other</code> must be a reference to a smart
|
||
pointer, or a reference to a smart <code>virtual_ptr</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(4) Moves <code>other</code> to this <code>virtual_ptr</code>. If <code>other</code> is a smart pointer or a
|
||
smart virtual pointer, the object pointer is moved from <code>other</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>(5) Sets the object pointer to <code>other</code>. Available only for plain
|
||
<code>virtual_ptr</code>s.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>other</code> is also a <code>virtual_ptr</code>, the v-table pointer is copied from it.
|
||
Otherwise, it is deduced from the object. The <code>Policy</code> must be the same for both
|
||
<code>virtual_ptr</code>s.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_final">final</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Other>
|
||
static auto final(Other&& obj);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Constructs a <code>virtual_ptr</code> from a reference to an object, or from a smart
|
||
pointer. It is assumed that the static and dynamic types are the same. The
|
||
v-table pointer is initialized from the <code>Policy::static_vptr</code> for the class,
|
||
which needs not be polymorphic.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_get">get</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto get() const -> element_type*;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a pointer to the object.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_operator">operator→</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto operator->() const -> element_type*;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a pointer to the object.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_operator_2">operator*</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto operator*() const -> element_type&;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a reference to the object.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_pointer">pointer</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto pointer() const;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a reference to the object pointer, which can be either a plain pointer
|
||
or a smart pointer.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_cast">cast</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename Other>
|
||
auto cast() const -> virtual_ptr<Other, Policy>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a <code>virtual_ptr</code> to the same object, cast to <code>Other</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_deduction_guide">Deduction guide</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<hr>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_non_members">Non-members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_virtual_shared_ptr">virtual_shared_ptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
using virtual_shared_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Convenience alias for <code>virtual_ptr<std::shared_ptr<Class>, Policy></code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_virtual_unique_ptr">virtual_unique_ptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
using virtual_unique_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Convenience alias for <code>virtual_ptr<std::unique_ptr<Class>, Policy></code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_final_virtual_ptr">final_virtual_ptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Policy, class Class>
|
||
inline auto final_virtual_ptr(Class&& obj);
|
||
|
||
template<class Class>
|
||
inline auto final_virtual_ptr(Class&& obj);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Utility functions, forwarding to <code>virtual_ptr<Class, Policy>::final</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>Policy</code> is not specified, <code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> is used.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_make_shared_virtual">make_shared_virtual</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<
|
||
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY, typename... T>
|
||
inline auto make_shared_virtual(T&&... args)
|
||
-> shared_virtual_ptr<Class, Policy>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Creates an object using <code>std::make_shared</code> and returns a <code>virtual_shared_ptr</code> to
|
||
it. The v-table pointer is initialized from the the <code>Policy::static_vptr</code> for
|
||
the class, which needs not be polymorphic.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_make_unique_virtual">make_unique_virtual</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<
|
||
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY, typename... T>
|
||
inline auto make_unique_virtual(T&&... args)
|
||
-> unique_virtual_ptr<Class, Policy>;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Creates an object using <code>std::make_unique</code> and returns a <code>virtual_unique_ptr</code> to
|
||
it. The v-table pointer is initialized from the the <code>Policy::static_vptr</code> for
|
||
the class, which needs not be polymorphic.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_operator_3">operator==</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Left, class Right, class Policy>
|
||
auto operator==(
|
||
const virtual_ptr<Left, Policy>& left,
|
||
const virtual_ptr<Right, Policy>& right) -> bool;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Compares two <code>virtual_ptr</code> objects for equality.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_operator_4">operator!=</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Left, class Right, class Policy>
|
||
auto operator!=(
|
||
const virtual_ptr<Left, Policy>& left,
|
||
const virtual_ptr<Right, Policy>& right) -> bool;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Compares two <code>virtual_ptr</code> objects for inequality.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_virtual_traits">virtual_traits</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_2">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/core.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class, class>
|
||
struct virtual_traits; // not defined
|
||
|
||
template<class Class, class Policy>
|
||
struct virtual_traits<..., Policy> {
|
||
using virtual_type = ...;
|
||
static auto peek(const T& arg) -> const ...&;
|
||
template<typename Derived> static auto cast(T& obj) -> ...;
|
||
template<class Other> using rebind = ...; // for smart virtual pointers
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_2">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Specializations of <code>virtual_traits</code> provide an interface for <code>method</code> and
|
||
<code>virtual_ptr</code> to manipulate virtual arguments.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_specializations">Specializations</h4>
|
||
<div class="paragraph">
|
||
<p>Specializations are provided for:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>virtual_ptr<T, Policy></code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>const virtual_ptr<T, Policy>&</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>T&</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>T&&</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>T*</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>std::shared_ptr<T></code>: defined in <boost/openmethod/interop/std_shared_ptr.hpp></p>
|
||
</li>
|
||
<li>
|
||
<p><code>const std::shared_ptr<T>&</code>: defined in <boost/openmethod/interop/std_shared_ptr.hpp></p>
|
||
</li>
|
||
<li>
|
||
<p><code>std::unique_ptr<T></code>: defined in <boost/openmethod/interop/std_unique_ptr.hpp></p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_2">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_virtual_type">virtual_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">using virtual_type = ...;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The class used for method selection. It must be registered in Policy.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For example, <code>virtual_type</code> in the following specializations are all <code>Class</code>:</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>virtual_traits<virtual_ptr<Class, Policy>></code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>virtual_traits<const virtual_ptr<std::shared_ptr<Class>&, Policy></code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>virtual_traits<Class&, Policy></code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>virtual_traits<const std::shared_ptr<Class>&, Policy></code></p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_peek">peek</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto peek(T arg) -> const ...&;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a value for the purpose of obtaining a v-table pointer for <code>arg</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For example, <code>peek</code> returns a <code>const T&</code> for a <code>T&</code>, a <code>const T&</code>, a <code>T&&</code>, and
|
||
a <code>std::shared_ptr<T></code>; and a <code>const virtual_ptr<Class, Policy>&</code> for a
|
||
<code>const virtual_ptr<Class, Policy>&</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_cast_2">cast</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename Derived>
|
||
static decltype(auto) cast(T& obj);</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Casts argument <code>obj</code> to the type expected by an overrider.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For example, if a method takes a <code>virtual_<Animal&></code>, an overrider for <code>Cat&</code>
|
||
uses <code>virtual_traits</code> to cast a <code>Animal&</code> to a <code>Cat&</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_rebind">rebind</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Other> using rebind = ...;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For smart pointers only. Rebinds the smart pointer to a different type. For
|
||
example, <code>virtual_traits<std::shared_ptr<T>, Policy>::rebind<U></code> is
|
||
<code>std::shared_ptr<U></code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_use_classes">use_classes</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_3">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/core.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class... Classes, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
struct use_classes {
|
||
use_classes();
|
||
~use_classes();
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Usage:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">use_classes<Classes...> some_unique_name; // at file scope</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_3">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>use_classes</code>, instantiated as a static object, registers <code>Classes</code> in <code>Policy</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Classes potentially involved in a method definition, an overrider, or a method
|
||
call must be registered via <code>use_classes</code>. A class may be registered multiple
|
||
times. A class and its direct bases must be listed together in one or more
|
||
instantiations of <code>use_classes</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Virtual and multiple inheritance are supported, as long as they don’t result in
|
||
a class lattice that contains repeated inheritance.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
The default value for <code>Policy</code> is the value of
|
||
<code>BOOST_OPENMETHOD_DEFAULT_REGISTRY</code> when <code><boost/openmethod/core.hpp></code> is
|
||
included. Subsequently changing it has no retroactive effect.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_3">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_constructor">constructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">use_classes();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Registers <code>Classes</code> and their inheritance relationships in <code>Policy</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_destructor">destructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">~use_classes();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Removes <code>Classes</code> and their inheritance relationships from <code>Policy</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_virtual">virtual_</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_4">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <code><boost/openmethod/core.hpp></code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<typename T>
|
||
struct virtual_;
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_4">Description</h4>
|
||
<div class="paragraph">
|
||
<p>Marks a formal parameter of a method as virtual. Requires a specialization of
|
||
<code>virtual_traits</code> for <code>T</code> and the <code>Policy</code> of the method. Specializations for
|
||
<code>T&</code>, <code>T&&</code>, <code>T*</code>, <code>std::unique_ptr<T></code>, <code>std::shared_ptr<T></code> and <code>const
|
||
std::shared_ptr<T>&</code> are provided. See the documentation of <code>virtual_traits</code> for
|
||
more information.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_inplace_vptr">inplace_vptr</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_5">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/inplace_vptr.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||
class inplace_vptr {
|
||
protected:
|
||
inplace_vptr();
|
||
~inplace_vptr();
|
||
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
|
||
};
|
||
|
||
template<class Class, class Base, class... MoreBases>
|
||
class inplace_vptr {
|
||
protected:
|
||
inplace_vptr();
|
||
~inplace_vptr();
|
||
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
|
||
// if sizeof(MoreBases...) > 0
|
||
};
|
||
|
||
} // namespace boost::openmethod</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_5">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>inplace_vptr</code> is a CRTP class template that embeds and manages a vptr across a
|
||
class hierarchy.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>Class</code> has no <code>Bases</code>, <code>inplace_vptr</code> adds a <code>boost_openmethod_vptr</code> private
|
||
member to <code>Class</code>. In either case, it sets the vptr to the v-table of <code>Class</code>
|
||
from <code>Policy</code>. It also creates a <code>boost_openmethod_vptr</code> friend function that
|
||
takes a a <code>const Class&</code> and returns the embedded vptr.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>Class</code> has has more than one base, the <code>boost_openmethod_vptr</code> friend
|
||
function is also created. It returns one of the embedded vptrs (it doesn’t
|
||
matter which one, as they all have the same value). This is to resolve
|
||
ambiguities</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>As part of its implementation, <code>inplace_vptr</code> may also declare one or two free
|
||
functions (<code>boost_openmethod_policy</code> and <code>boost_openmethod_bases</code>) at certain
|
||
levels of the hierarchy.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_4">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_constructor_2">constructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">inplace_vptr();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Sets the vptr to the v-table for Class, obtained from <code>Policy</code>. If <code>Policy</code>
|
||
contains <code>indirect_vptr</code>, an additional level of indirection is added, thus
|
||
preserving the validity of the pointer across calls to <code>initialize</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_destructor_2">destructor</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">~inplace_vptr();</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For each <code>Base</code>, sets the vptr to the v-table for that base.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_free_functions">Free Functions</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto boost_openmethod_vptr(const Class& obj) -> vptr_type;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns the vptr embedded in <code>obj</code>.
|
||
## abstract_policy</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_6">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct abstract_policy {};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_6">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>abstract_policy</code> is a required base class for a policy. It makes it possible
|
||
for meta-functions such as <code>use_classes</code> to discriminate between user classes
|
||
and the (optional) policy class.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_domain">domain</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_7">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
template<class Policy>
|
||
struct domain {
|
||
template<class Class> static vptr_type static_vptr;
|
||
// unspecified members
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_7">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>domain</code> is a registry of classes and methods registered in a <em>Policy</em>,
|
||
and their dispatch tables.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_5">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_static_vptr">static_vptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static vptr_type static_vptr;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Contains the pointer to the v-table for <em>Class</em>. Set by <code>initialize</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_basic_policy">basic_policy</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_8">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
namespace policies {
|
||
|
||
template<class Policy, class... Facets>
|
||
struct basic_policy : abstract_policy, domain<Policy>, Facets... {
|
||
template<class Facet>
|
||
static constexpr bool has = /*unspecified*/;
|
||
|
||
template<class NewPolicy>
|
||
using fork = /*unspecified*/;
|
||
|
||
template<class... Facets>
|
||
using with = /*unspecified*/;
|
||
|
||
template<class... Facets>
|
||
using without = /*unspecified*/;
|
||
};
|
||
|
||
struct release : basic_policy<release, ...> {};
|
||
|
||
struct debug : release::add<...> {};
|
||
|
||
} // policies
|
||
|
||
#ifdef NDEBUG
|
||
using default_registry = policies::release;
|
||
#else
|
||
using default_registry = policies::debug;
|
||
#endif
|
||
|
||
} // boost::openmethod</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_headers">Headers</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>. Also available via
|
||
<code><boost/openmethod/core.hpp></code> and <code><boost/openmethod.hpp></code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_8">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>basic_policy</code> implements a policy, which consists of a a collection of methods,
|
||
classes, dispatch data, and policys, which specify how to obtain a pointer to a
|
||
v-table from an object, how to report errors, whether to perform runtime sanity
|
||
checks, etc.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>basic_policy</code> has state. It uses the Curiously Recurring Template Pattern to
|
||
allow distinct policies to have distinct sets of static variables.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_6">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_has">has</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Facet>
|
||
static constexpr bool has;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Evaluates to <code>true</code> if <em>Policy</em> contains <em>Facet</em>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_fork">fork</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class NewPolicy>
|
||
using fork;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Creates a new policy from an existing one. <em>NewPolicy</em> does not share static
|
||
variables with the original <em>Policy</em>. The new policy does not retain any
|
||
knowledge of the classes and methods registered in the original.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>fork</code> forks the policys in the policy as well: any policy instantiated from a
|
||
class template is assumed to take a policy as its first template argument. The
|
||
template is re-instantiated with the new policy as the first arguments, while
|
||
the other arguments remain the same.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_with">with</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class... Facets>
|
||
using with;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">Requires</dt>
|
||
<dd>
|
||
<p><em>Facets</em> is a list of classes that derive from <code>policy</code>.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Returns</dt>
|
||
<dd>
|
||
<p>A new policy containing <em>Facets</em>, and the policys from the original
|
||
that do not have the same category as <em>Facets</em>.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Examples</dt>
|
||
<dd>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>struct dyn_load : default_registry::fork<dyn_load>::with<indirect_vptr> {};</code><br>
|
||
Creates a policy just like <code>default_registry</code>, with an extra indirection added
|
||
to the v-table pointers. This policy is suitable for use with dynamic loading.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>struct release_with_diags : release::fork<release_with_diags>::with<basic_error_output<release_with_diags>> {};</code><br>
|
||
Creates a policy just like <code>release</code>, except that it prints a diagnostic
|
||
message before terminating with <code>abort()</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>struct default_throw : default_registry::fork<default_throw>::with<throw_error_handler> {};</code><br>
|
||
Creates a policy just like <code>default_registry</code>, except that it reports errors by
|
||
throwing exceptions, instead of calling a <code>std::function</code> like the default
|
||
error handler does.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_without">without</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class... Facets>
|
||
using without;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">Requires</dt>
|
||
<dd>
|
||
<p><em>Facets</em> is a list of policy categories.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Returns</dt>
|
||
<dd>
|
||
<p>A new policy containing the policys from the original that do not have
|
||
the same category as <em>Facets</em>.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Examples</dt>
|
||
<dd>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>struct use_map : default_registry::fork<use_map>::with<vptr_map<use_map>>::without<type_hash> {};</code><br>
|
||
Creates a policy just like <code>default_registry</code>, except that it stores pointers to
|
||
v-table in a <code>std::unordered_map</code>. Also removes the hash function, since it
|
||
will not be used.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_non_members_2">Non-members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_release">release</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct release;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A policy that contains policys <code>std_rtti</code>, <code>fast_perfect_hash</code>, <code>vptr_vector</code> and
|
||
<code>default_error_handler</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_debug">debug</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct debug;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>release</code> policy with additional policy implementations <code>runtime_checks</code>,
|
||
<code>basic_error_output</code> and basic_trace_output.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<div class="title">Note</div>
|
||
</td>
|
||
<td class="content">
|
||
<code>debug</code> extends <code>release</code> but it does not a fork it. Both policies use the
|
||
same <code>domain</code>.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_default_registry">default_registry</h5>
|
||
<div class="paragraph">
|
||
<p>An alias for <code>release</code> if <code>NDEBUG</code> is defined, and for <code>debug</code> otherwise.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_policy">policy</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_9">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct policy {
|
||
static auto finalize() -> void;
|
||
};
|
||
|
||
} // boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_9">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>policy</code> is the base class of all policys. It provides an empty <code>finalize</code> static
|
||
function which can be overriden (via shadowing) by derived classes.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_7">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_finalize">finalize</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto finalize() -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Does nothing.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_rtti">rtti</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_10">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct rtti : policy {};
|
||
|
||
} // boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_10">Description</h4>
|
||
<div class="paragraph">
|
||
<p>The <code>rtti</code> policy provides type information for classes and objects, implements
|
||
downcast in presence of virtual inheritance, and writes descriptions of types to
|
||
an <code>ostream</code>-like object.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_requirements">Requirements</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_is_polymorphic">is_polymorphic</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static constexpr bool is_polymorphic;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>true</code> if <code>Class</code> is polymorphic.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_static_type">static_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static auto static_type() -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a <code>type_id</code> for <code>Class</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_type">dynamic_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static auto dynamic_type(const Class& obj) -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a <code>type_id</code> for an object’s dynamic type.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_type_name">type_name</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename Stream>
|
||
static auto type_name(type_id type, Stream& stream) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Writes a description of <code>type</code> to <code>stream</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This requirement is optional. <code>rtti</code> provides a default implementation that writes <code>typeid({type})</code> to <code>stream</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_type_index">type_index</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto type_index(type_id type) -> /* unspecified */;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a unique key for <code>type</code>. Required only for RTTI systems that assign more
|
||
than one type "identifiers" to a type. For example, standard RTTI allows
|
||
implementations to have multiple instances of <code>std::type_info</code> for the same
|
||
type.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_cast_ref">dynamic_cast_ref</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename D, typename B>
|
||
static auto dynamic_cast_ref(B&& obj) -> D;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Casts <code>obj</code> to <code>D</code>. Required only if using virtual inheritance.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_std_rtti">std_rtti</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_11">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/std_rtti.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct std_rtti : rtti {
|
||
template<class Class>
|
||
static auto static_type() -> type_id;
|
||
|
||
template<class Class>
|
||
static auto dynamic_type(const Class& obj) -> type_id;
|
||
|
||
template<typename Stream>
|
||
static auto type_name(type_id type, Stream& stream) -> void;
|
||
|
||
static auto type_index(type_id type) -> std::type_index;
|
||
|
||
template<typename D, typename B>
|
||
static auto dynamic_cast_ref(B&& obj) -> D;
|
||
};
|
||
|
||
} // boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_11">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>std_rtti</code> is an implementation of the <code>rtti</code> policy that uses standard RTTI.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_8">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_static_type_2">static_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static auto static_type() -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Return the address of <code>Class’s `type_info</code>, cast to a <code>type_id</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_type_2">dynamic_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static auto dynamic_type(const Class& obj) -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Return the address of <code>obj</code>'s <code>type_info</code>, cast to a <code>type_id</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_type_name_2">type_name</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename Stream>
|
||
static auto type_name(type_id type, Stream& stream) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Write the demangled name of the class identified by <code>type</code> to <code>stream</code>.
|
||
Execute <code>stream << reinterpret_cast<const std::type_info*>(type)→name()</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_type_index_2">type_index</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto type_index(type_id type) -> /*unspecified*/;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Return <code>std::type_index(<strong>reinterpret_cast<const std::type_info</strong>>(type))</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The function is required because C++ does <strong>not</strong> guarantee that there is a single
|
||
instance of <code>std::type_info</code> for each specific type.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_cast_ref_2">dynamic_cast_ref</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename Derived, typename Base>
|
||
static auto dynamic_cast_ref(Base&& obj) -> Derived;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Cast <code>obj</code> using the <code>dynamic_cast</code> operator.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_deferred_static_rtti">deferred_static_rtti</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_12">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct deferred_static_rtti : rtti {};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_12">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>deferred_static_rtti</code> is a policy that defers collection of static type ids.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Some custom RTTI systems rely on static constructors to assign type ids.
|
||
OpenMethod itself relies on static constructors to register classes, methods and
|
||
overriders, calling the <code>static_type</code> function from the <code>rtti</code> policy in the
|
||
process. This can result in collecting the type ids <em>before</em> they have been
|
||
initialized. Adding this policy to a policy moves the collection of type ids to
|
||
<code>initialize</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_minimal_rtti">minimal_rtti</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_13">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct minimal_rtti : rtti {
|
||
template<class Class>
|
||
static constexpr bool is_polymorphic = false;
|
||
|
||
template<typename Class>
|
||
static auto static_type() -> type_id;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_13">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>minimal_rtti</code> is an implementation of the <code>rtti</code> policy that only uses static
|
||
type information.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>minimal_rtti</code> provides the only function strictly required for the <code>rtti</code>
|
||
policy.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This policy can be used in programs that call methods solely via
|
||
<code>virtual_ptr</code>s created with the "final" constructs. Virtual inheritance
|
||
is not supported. Classes are not required to be polymorphic.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_9">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_is_polymorphic_2">is_polymorphic</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static constexpr bool is_polymorphic = false;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This policy does not support polymorphic classes.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_static_type_3">static_type</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
static auto static_type() -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns the address of a local static <code>char</code> variable, cast to <code>type_id</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_extern_vptr">extern_vptr</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_14">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct extern_vptr : policy {};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_14">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>extern_vptr</code> is a policy that stores and returns pointers to v-tables for
|
||
registered classes.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_requirements_2">Requirements</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_register_vptrs">register_vptrs</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename ForwardIterator>
|
||
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>ForwardIterator</code> is a forward iterator over a range of objects that contain
|
||
information about the type ids and the vptr of a registered class. They have the
|
||
following member functions:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">auto type_id_begin() const -> type_id_forward_iterator;
|
||
auto type_id_end() const -> type_id_forward_iterator;
|
||
auto vptr() const -> const vptr_type&;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>type_id_begin</code> and <code>type_id_end</code> return iterators delimiting a range of
|
||
`type_id`s for a class.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>vptr</code> returns a <em>reference</em> to a <em>static</em> variable containing a pointer to the
|
||
v-table for a the class. Its value is set by <code>initialize</code>. While the value of
|
||
the variable changes with each call to <code>initialize</code>, the variable itself remains
|
||
the same.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_indirect_vptr">indirect_vptr</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_15">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">struct indirect_vptr : policy {};</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_15">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>indirect_vptr</code> is a policy that makes <code>virtual_ptr</code>s and <code>inplace_vptr</code> use
|
||
pointers to pointers to v-tables, instead of straight pointers. As a
|
||
consequence, they remain valid after a call to <code>initialize</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_requirements_3">Requirements</h4>
|
||
<div class="paragraph">
|
||
<p>None. The policy is its own implementation.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_vptr_vector">vptr_vector</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_16">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/vptr_vector.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
template<class Policy>
|
||
class vptr_vector : Base {
|
||
public:
|
||
template<typename ForwardIterator>
|
||
static auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
|
||
|
||
template<class Class>
|
||
static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_16">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>vptr_vector</code> is an implementation or <code>external_vptr</code> that keeps the pointers to
|
||
the v-tables in a <code>std::vector</code>. If <code>Policy</code> contains <code>indirect_vptr</code>, a level
|
||
of indirection is added, making the policy usable in presence of dynamic
|
||
loading.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>Policy</code> is the policy containing the policy.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_10">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_register_vptrs_2">register_vptrs</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename ForwardIterator>
|
||
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Stores the pointers to v-tables in a vector, indexed by the (possibly hashed)
|
||
<code>type_id`s of the classes registered in `Policy</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>Policy</code> contains a <code>type_hash</code> policy, call its <code>hash_initialize</code>
|
||
function, and uses it to convert the <code>type_id</code>s to an index.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_vptr">dynamic_vptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
auto dynamic_vptr(const Class& object) -> const vptr_type&;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a pointer to the v-table for <code>object</code> (by reference).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Obtains a <code>type_id</code> for <code>object</code> using <code>Policy::dynamic_type</code>. If <em>Policy</em>
|
||
contains a <code>type_hash</code> policy, uses it to convert the result to an index;
|
||
otherwise, uses the <code>type_id</code> as the index.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_vptr_map">vptr_map</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_17">Synopsis</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
### Synopsis
|
||
|
||
template<class Policy, class MapAdaptor = mp11::mp_quote<std::unordered_map>>
|
||
class vptr_map : public extern_vptr {
|
||
public:
|
||
template<typename ForwardIterator>
|
||
static auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
|
||
|
||
template<class Class>
|
||
static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_17">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>vptr_map</code> is an implementation of <code>external_vptr that stores the pointers to
|
||
the v-tables in a map. If `Policy</code> contains <code>indirect_vptr</code>, a level of
|
||
indirection is added, making the policy usable in presence of dynamic loading.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>Policy</code> is the policy containing the policy.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>MapAdaptor</code> is a Boost.Mp11 quoted metafunction that returns a map type.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_11">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_register_vptrs_3">register_vptrs</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename ForwardIterator>
|
||
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Stores the pointers to v-tables in a <em>Map</em>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_dynamic_vptr_2">dynamic_vptr</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Class>
|
||
auto dynamic_vptr(const Class& object) -> const vptr_type&;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns a pointer to the v-table for <code>object</code> (by reference).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <em>Policy</em> contains the <code>runtime_checks</code> policy, checks if <em>Class</em> is
|
||
registered. If it is not, and <em>Policy</em> contains a <code>error_handler</code> policy, calls
|
||
its <code>error</code> function; then calls <code>abort</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_type_hash">type_hash</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_18">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct type_hash : policy {};
|
||
|
||
} // boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_18">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>type_hash</code> is a policy that provides a hash function for a fixed set of
|
||
<code>type_id</code>s.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_requirements_4">Requirements</h4>
|
||
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_hash_type_id">hash_type_id</h4>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto hash_type_id(type_id type) -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns the hash of <code>type</code>.</p>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_hash_initialize">hash_initialize</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename ForwardIterator>
|
||
static auto hash_initialize(ForwardIterator first, ForwardIterator last)
|
||
-> Report;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finds a hash function for the <code>type_id</code>s in the range <code>[first, last)</code>.
|
||
<code>ForwardIterator</code> is the same as in <code>vptr_vector::register_vptrs</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>hash_initialize</code> returns a <code>Report</code> object which is required to have two
|
||
members, <code>first</code> and <code>last</code>, which define the range <code>[first, last)</code> of the
|
||
possible output values of the hash function.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_fast_perfect_hash">fast_perfect_hash</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_19">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/fast_perfect_hash.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">class fast_perfect_hash : type_hash
|
||
{
|
||
public:
|
||
static auto hash_type_id(type_id type) -> type_id;
|
||
template<typename ForwardIterator>
|
||
static auto hash_initialize(ForwardIterator first, ForwardIterator last) -> Report;
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_19">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>fast_perfect_hash</code> implements a very fast, perfect (but not minimal) hash
|
||
function for <code>type_id</code>s.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_12">Members</h4>
|
||
<div class="paragraph">
|
||
<p>Find two factors</p>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_hash_type_id_2">hash_type_id</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto hash_type_id(type_id type) -> type_id;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Returns <code>(type * M) >> S</code>, where <code>M</code> and <code>S</code> are factors found by
|
||
<code>hash_initialize</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If the policy has a <code>runtime_checks</code> policy, <code>hash_type_id</code> checks that <code>type</code>
|
||
corresponds to a registered class. If not, it reports a <code>unknown_class_error</code>
|
||
using the policy’s error_handler policy, if present, then calls <code>abort</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_hash_initialize_2">hash_initialize</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<typename ForwardIterator>
|
||
auto hash_initialize(ForwardIterator first, ForwardIterator last) -> Report;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finds factors <code>M</code> and <code>S</code> such that <code>hash_type_id</code> is a collision-free hash
|
||
function.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If no such factors cannot be found, <code>hash_initialize</code> reports a
|
||
<code>hash_search_error</code> using the policy’s error_handler policy, if present, the
|
||
calls <code>abort</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If the policy has a <code>trace</code> policy, <code>hash_initialize</code> uses it to write a
|
||
summary of the search.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_error_handler">error_handler</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_20">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_policy.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
|
||
|
||
namespace policies {
|
||
|
||
struct error_handler;
|
||
|
||
}
|
||
|
||
struct openmethod_error {};
|
||
|
||
struct not_implemented_error : openmethod_error {
|
||
type_id method;
|
||
std::size_t arity;
|
||
static constexpr std::size_t max_types = 16;
|
||
type_id types[max_types];
|
||
};
|
||
|
||
struct unknown_class_error : openmethod_error {
|
||
type_id type;
|
||
};
|
||
|
||
struct hash_search_error : openmethod_error {
|
||
std::size_t attempts;
|
||
std::size_t buckets;
|
||
};
|
||
|
||
struct type_mismatch_error : openmethod_error {
|
||
type_id type;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_20">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>error_handler</code> is a policy that handles errors.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>When an error is encountered, either during <code>initialize</code> or method dispatch, the
|
||
program is terminated via a call to <code>abort</code>. If this policy is present in the
|
||
policy, its <code>error</code> function is called with an error object. It can prevent
|
||
termination by throwing an exception.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_requirements_5">Requirements</h4>
|
||
<div class="paragraph">
|
||
<p>Implementations of <code>error_handler</code> must provide the following functions:</p>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_error">error</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto error(const T&) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_default_error_handler">default_error_handler</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_21">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/default_error_handler.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
template<class Policy>
|
||
class default_error_handler : public error_handler {
|
||
public:
|
||
using error_variant = std::variant<
|
||
openmethod_error, not_implemented_error, unknown_class_error,
|
||
hash_search_error, type_mismatch_error, static_slot_error,
|
||
static_stride_error>;
|
||
using function_type = std::function<void(const error_variant& error)>;
|
||
|
||
template<class Error>
|
||
static auto error(const Error& error) -> void;
|
||
static auto set_error_handler(error_handler_type handler) -> function_type;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_21">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>default_error_handler</code> is an implementation of <code>error_handler</code> that calls a
|
||
<code>std::function</code> to handle the error.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_13">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_error_2">error</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Error>
|
||
static auto error(const Error& error) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Calls the function last set via <code>set_error_handler</code> or, if it was never called,
|
||
and if <em>Policy</em> contains an <code>output</code> policy, use it to print a description
|
||
of <code>error</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_error_3">error</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static auto set_error_handler(function_type handler) -> function_type;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Sets <code>handler</code> as the function to call in case of error.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_throw_error_handler">throw_error_handler</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_22">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/throw_error_handler.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
struct throw_error_handler : error_handler {
|
||
template<class Error>
|
||
[[noreturn]] static auto error(const Error& error) -> void;
|
||
};
|
||
|
||
} // boost::openmethod::policies</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_22">Description</h4>
|
||
<div class="paragraph">
|
||
<p>throw_error_handler is an implementation of the <code>error_handler</code> policy that
|
||
throws the error as an exception.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_14">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_error_4">error</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">template<class Error>
|
||
[[noreturn]] static auto error(const Error& error) -> void;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Throws <code>error</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_basic_error_output">basic_error_output</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_23">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_error_output.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
template<class Policy, typename Stream = /*unspecified*/>
|
||
struct basic_error_output : output {
|
||
static Stream error_stream;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_23">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>basic_error_output</code> is an implementation of <code>output</code> that writes error
|
||
messages to a <code>LightweightOutputStream</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_15">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_error_stream">error_stream</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">Stream error_stream;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Initialized by the default constructor of <code>Stream</code>. It is the responsibility of
|
||
the program to initializate it if needed, e.g., for a <code>std::ofstream</code>, to open
|
||
it.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_basic_trace_output">basic_trace_output</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_synopsis_24">Synopsis</h4>
|
||
<div class="paragraph">
|
||
<p>Defined in <boost/openmethod/policies/basic_trace_output.hpp>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod::policies {
|
||
|
||
template<class Policy, typename Stream = /*unspecified*/>
|
||
struct basic_trace_output : trace {
|
||
static bool trace_enabled;
|
||
static Stream trace_stream;
|
||
};
|
||
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_24">Description</h4>
|
||
<div class="paragraph">
|
||
<p><code>basic_error_output</code> is an implementation of <code>trace</code> that writes error
|
||
messages to a <code>LightweightOutputStream</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_members_16">Members</h4>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_trace_enabled">trace_enabled</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static bool trace_enabled;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Set to <code>true</code> if environment variable <code>BOOST_OPENMETHOD_TRACE</code> is set to <code>1</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="virtual_ptr_trace_stream">trace_stream</h5>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="rouge highlight"><code data-lang="c++">static Stream trace_stream;</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Initialized by the default constructor of <code>Stream</code>. It is the responsibility of
|
||
the program to prepare it for output if needed, e.g., for a <code>std::ofstream</code>, to
|
||
open it.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="virtual_ptr_restrictedoutputstream">LightweightOutputStream</h3>
|
||
<div class="sect3">
|
||
<h4 id="virtual_ptr_description_25">Description</h4>
|
||
<div class="paragraph">
|
||
<p>LightweightOutputStream is a concept describing a <code>std::ostream</code>-like class with
|
||
a reduced set of operations.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>While convenient, <code>std::ostream</code> and its implementations constitute a sizeable
|
||
piece of code, which may make it unsuitable for certain applications. OpenMethod
|
||
uses a small subset of the operations supported by <code>std::ostream</code>. By default,
|
||
the library uses a lightweight implementation based on the C stream functions.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Implementations of <code>LightweightOutputStream</code> provide the following functions:</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all stretch">
|
||
<colgroup>
|
||
<col style="width: 50%;">
|
||
<col style="width: 50%;">
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">Name</th>
|
||
<th class="tableblock halign-left valign-top">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>LightweightOutputStream& operator<<(LightweightOutputStream& os, const char* str)</p>
|
||
</div></div></td>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>Write a null-terminated string <code>str</code> to <code>os</code></p>
|
||
</div></div></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>LightweightOutputStream& operator<<(LightweightOutputStream& os, const std::string_view& view)</p>
|
||
</div></div></td>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>Write a view to `os</p>
|
||
</div></div></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>LightweightOutputStream& operator<<(LightweightOutputStream& os, const void* value)</p>
|
||
</div></div></td>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>Write a representation of a pointer to <code>os</code></p>
|
||
</div></div></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>LightweightOutputStream& operator<<(LightweightOutputStream& os, std::size_t value)</p>
|
||
</div></div></td>
|
||
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
|
||
<p>Write an unsigned integer to <code>os</code></p>
|
||
</div></div></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="footer">
|
||
<div id="footer-text">
|
||
Last updated 2025-06-22 13:38:14 -0400
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|