<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Smart Objects, an alternative approach to overloading operator dot</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
<meta name="keywords" content="overloading, operator, smart, objects, references, C++, proposal, ISO/IEC, JTC1, SC22, WG21, N4495"></meta>

<style type="text/css">

#docinfo table {
  border: none;
  border-spacing: 0px;
}

h2 {
  clear: both;
}

@media screen and (min-width: 1280px) {

#info {
  position: fixed;
  left: 80%;
  top: 0;
}

#docinfo, #toc { width: 95%; }

#body {
  width: 80%%;
}

}

#toc ul { margin: 0; }
#toc li { margin: 0; }

#toc { margin-bottom: 1em; }

/* github-like markdown */

body {
  font-family: Helvetica, arial, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  padding-top: 10px;
  padding-bottom: 10px;
  background-color: white;
  padding: 30px;
  color: #333;
}
 
body > *:first-child {
  margin-top: 0 !important;
}
 
body > *:last-child {
  margin-bottom: 0 !important;
}
 
a {
  color: #4183C4;
  text-decoration: none;
}
 
a.absent {
  color: #cc0000;
}
 
a.anchor {
  display: block;
  padding-left: 30px;
  margin-left: -30px;
  cursor: pointer;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
}
 
h1, h2, h3, h4, h5, h6 {
  margin: 20px 0 10px;
  padding: 0;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
  cursor: text;
  position: relative;
}
 
h2:first-child, h1:first-child, h1:first-child + h2, h3:first-child, h4:first-child, h5:first-child, h6:first-child {
  margin-top: 0;
  padding-top: 0;
}
 
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
  text-decoration: none;
}
 
h1 tt, h1 code {
  font-size: inherit;
}
 
h2 tt, h2 code {
  font-size: inherit;
}
 
h3 tt, h3 code {
  font-size: inherit;
}
 
h4 tt, h4 code {
  font-size: inherit;
}
 
h5 tt, h5 code {
  font-size: inherit;
}
 
h6 tt, h6 code {
  font-size: inherit;
}
 
h1 {
  font-size: 28px;
  color: black;
}
 
h2 {
  font-size: 24px;
  border-bottom: 1px solid #cccccc;
  color: black;
}
 
h3 {
  font-size: 18px;
}
 
h4 {
  font-size: 16px;
}
 
h5 {
  font-size: 14px;
}
 
h6 {
  color: #777777;
  font-size: 14px;
}
 
p, blockquote, ul, ol, dl, li, table, pre {
  margin: 15px 0;
}
 
hr {
  background: transparent url("http://tinyurl.com/bq5kskr") repeat-x 0 0;
  border: 0 none;
  color: #cccccc;
  height: 4px;
  padding: 0;
}
 
body > h2:first-child {
  margin-top: 0;
  padding-top: 0;
}
 
body > h1:first-child {
  margin-top: 0;
  padding-top: 0;
}
 
body > h1:first-child + h2 {
  margin-top: 0;
  padding-top: 0;
}
 
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
  margin-top: 0;
  padding-top: 0;
}
 
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
  margin-top: 0;
  padding-top: 0;
}
 
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
  margin-top: 0;
}
 
li p.first {
  display: inline-block;
}
 
ul, ol {
  padding-left: 30px;
}
 
ul :first-child, ol :first-child {
  margin-top: 0;
}
 
ul :last-child, ol :last-child {
  margin-bottom: 0;
}
 
dl {
  padding: 0;
}
 
dl dt {
  font-size: 14px;
  font-weight: bold;
  font-style: italic;
  padding: 0;
  margin: 15px 0 5px;
}
 
dl dt:first-child {
  padding: 0;
}
 
dl dt > :first-child {
  margin-top: 0;
}
 
dl dt > :last-child {
  margin-bottom: 0;
}
 
dl dd {
  margin: 0 0 15px;
  padding: 0 15px;
}
 
dl dd > :first-child {
  margin-top: 0;
}
 
dl dd > :last-child {
  margin-bottom: 0;
}
 
blockquote {
  border-left: 4px solid #dddddd;
  padding: 0 15px;
  color: #777777;
}
 
blockquote > :first-child {
  margin-top: 0;
}
 
blockquote > :last-child {
  margin-bottom: 0;
}
 
table {
  padding: 0;
}
table tr {
  border-top: 1px solid #cccccc;
  background-color: white;
  margin: 0;
  padding: 0;
}
 
table tr:nth-child(2n) {
  background-color: #f8f8f8;
}
 
table tr th {
  font-weight: bold;
  border: 1px solid #cccccc;
  text-align: left;
  margin: 0;
  padding: 6px 13px;
}
 
table tr td {
  border: 1px solid #cccccc;
  text-align: left;
  margin: 0;
  padding: 6px 13px;
}
 
table tr th :first-child, table tr td :first-child {
  margin-top: 0;
}
 
table tr th :last-child, table tr td :last-child {
  margin-bottom: 0;
}
 
img {
  max-width: 100%;
}
 
span.frame {
  display: block;
  overflow: hidden;
}
 
span.frame > span {
  border: 1px solid #dddddd;
  display: block;
  float: left;
  overflow: hidden;
  margin: 13px 0 0;
  padding: 7px;
  width: auto;
}
 
span.frame span img {
  display: block;
  float: left;
}
 
span.frame span span {
  clear: both;
  color: #333333;
  display: block;
  padding: 5px 0 0;
}
 
span.align-center {
  display: block;
  overflow: hidden;
  clear: both;
}
 
span.align-center > span {
  display: block;
  overflow: hidden;
  margin: 13px auto 0;
  text-align: center;
}
 
span.align-center span img {
  margin: 0 auto;
  text-align: center;
}
 
span.align-right {
  display: block;
  overflow: hidden;
  clear: both;
}
 
span.align-right > span {
  display: block;
  overflow: hidden;
  margin: 13px 0 0;
  text-align: right;
}
 
span.align-right span img {
  margin: 0;
  text-align: right;
}
 
span.float-left {
  display: block;
  margin-right: 13px;
  overflow: hidden;
  float: left;
}
 
span.float-left span {
  margin: 13px 0 0;
}
 
span.float-right {
  display: block;
  margin-left: 13px;
  overflow: hidden;
  float: right;
}
 
span.float-right > span {
  display: block;
  overflow: hidden;
  margin: 13px auto 0;
  text-align: right;
}
 
code, tt {
  margin: 0 2px;
  padding: 0 5px;
  white-space: nowrap;
  border: 1px solid #eaeaea;
  background-color: #f8f8f8;
  border-radius: 3px;
}
 
pre code {
  margin: 0;
  padding: 0;
  white-space: pre;
  border: none;
  background: transparent;
}
 
.highlight pre {
  background-color: #f8f8f8;
  border: 1px solid #cccccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}
 
pre {
  background-color: #f8f8f8;
  border: 1px solid #cccccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}
 
pre code, pre tt {
  background-color: transparent;
  border: none;
}

/*

Highlight style
github.com style (c) Vasily Polovnyov <vast@whiteants.net>

*/

.hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  color: #333;
  background: #f8f8f8;
  -webkit-text-size-adjust: none;
}

.hljs-comment,
.diff .hljs-header,
.hljs-javadoc {
  color: #998;
  font-style: italic;
}

.hljs-keyword,
.css .rule .hljs-keyword,
.hljs-winutils,
.nginx .hljs-title,
.hljs-subst,
.hljs-request,
.hljs-status {
  color: #333;
  font-weight: bold;
}

.hljs-number,
.hljs-hexcolor,
.ruby .hljs-constant {
  color: #008080;
}

.hljs-string,
.hljs-tag .hljs-value,
.hljs-phpdoc,
.hljs-dartdoc,
.tex .hljs-formula {
  color: #d14;
}

.hljs-title,
.hljs-id,
.scss .hljs-preprocessor {
  color: #900;
  font-weight: bold;
}

.hljs-list .hljs-keyword,
.hljs-subst {
  font-weight: normal;
}

.hljs-class .hljs-title,
.hljs-type,
.vhdl .hljs-literal,
.tex .hljs-command {
  color: #458;
  font-weight: bold;
}

.hljs-tag,
.hljs-tag .hljs-title,
.hljs-rule .hljs-property,
.django .hljs-tag .hljs-keyword {
  color: #000080;
  font-weight: normal;
}

.hljs-attribute,
.hljs-variable,
.lisp .hljs-body,
.hljs-name {
  color: #008080;
}

.hljs-regexp {
  color: #009926;
}

.hljs-symbol,
.ruby .hljs-symbol .hljs-string,
.lisp .hljs-keyword,
.clojure .hljs-keyword,
.scheme .hljs-keyword,
.tex .hljs-special,
.hljs-prompt {
  color: #990073;
}

.hljs-built_in {
  color: #0086b3;
}

.hljs-preprocessor,
.hljs-pragma,
.hljs-pi,
.hljs-doctype,
.hljs-shebang,
.hljs-cdata {
  color: #999;
  font-weight: bold;
}

.hljs-deletion {
  background: #fdd;
}

.hljs-addition {
  background: #dfd;
}

.diff .hljs-change {
  background: #0086b3;
}

.hljs-chunk {
  color: #aaa;
}


</style>

<script>
!function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return window.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){var n=(e.className+" "+(e.parentNode?e.parentNode.className:"")).split(/\s+/);return n=n.map(function(e){return e.replace(/^lang(uage)?-/,"")}),n.filter(function(e){return N(e)||/no(-?)highlight|plain|text/.test(e)})[0]}function i(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function o(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset<r[0].offset?e:r:"start"==r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value)+'"'}l+="<"+t(e)+Array.prototype.map.call(e.attributes,r).join("")+">"}function u(e){l+="</"+t(e)+">"}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);f.reverse().forEach(o)}else"start"==g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function c(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,o){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),o&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&o.tE&&(a.tE+=(a.e?"|":"")+o.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(i(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,o);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function s(e,t,a,i){function o(e,n){for(var t=0;t<n.c.length;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function f(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=E.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":x.classPrefix,i='<span class="'+a,o=t?"":"</span>";return i+=e+'">',i+n+o}function d(){if(!L.k)return n(y);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(y);r;){e+=n(y.substr(t,r.index-t));var a=g(L,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(y)}return e+n(y.substr(t))}function h(){if(L.sL&&!w[L.sL])return n(y);var e=L.sL?s(L.sL,y,!0,M[L.sL]):l(y);return L.r>0&&(B+=e.r),"continuous"==L.subLanguageMode&&(M[L.sL]=e.top),p(e.language,e.value,!1,!0)}function b(){return void 0!==L.sL?h():d()}function v(e,t){var r=e.cN?p(e.cN,"",!0):"";e.rB?(k+=r,y=""):e.eB?(k+=n(t)+r,y=""):(k+=r,y=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(y+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(y+=t),k+=b();do L.cN&&(k+="</span>"),B+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),y="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(f(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"<unnamed>")+'"');return y+=t,t.length||1}var E=N(e);if(!E)throw new Error('Unknown language: "'+e+'"');c(E);var R,L=i||E,M={},k="";for(R=L;R!=E;R=R.parent)R.cN&&(k=p(R.cN,"",!0)+k);var y="",B=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),R=L;R.parent;R=R.parent)R.cN&&(k+="</span>");return{r:B,value:k,language:e,top:L}}catch(S){if(-1!=S.message.indexOf("Illegal"))return{r:0,value:n(t)};throw S}}function l(e,t){t=t||x.languages||Object.keys(w);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(N(n)){var t=s(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function f(e){return x.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,x.tabReplace)})),x.useBR&&(e=e.replace(/\n/g,"<br>")),e}function g(e,n,t){var r=n?E[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=a(e);if(!/no(-?)highlight|plain|text/.test(n)){var t;x.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):t=e;var r=t.textContent,i=n?s(n,r,!0):l(r),c=o(t);if(c.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=i.value,i.value=u(c,o(p),r)}i.value=f(i.value),e.innerHTML=i.value,e.className=g(e.className,n,i.language),e.result={language:i.language,re:i.r},i.second_best&&(e.second_best={language:i.second_best.language,re:i.second_best.r})}}function d(e){x=i(x,e)}function h(){if(!h.called){h.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function b(){addEventListener("DOMContentLoaded",h,!1),addEventListener("load",h,!1)}function v(n,t){var r=w[n]=t(e);r.aliases&&r.aliases.forEach(function(e){E[e]=n})}function m(){return Object.keys(w)}function N(e){return w[e]||w[E[e]]}var x={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},w={},E={};return e.highlight=s,e.highlightAuto=l,e.fixMarkup=f,e.highlightBlock=p,e.configure=d,e.initHighlighting=h,e.initHighlightingOnLoad=b,e.registerLanguage=v,e.listLanguages=m,e.getLanguage=N,e.inherit=i,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("cpp",function(t){var i={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary intmax_t uintmax_t int8_t uint8_t int16_t uint16_t int32_t uint32_t  int64_t uint64_t int_least8_t uint_least8_t int_least16_t uint_least16_t int_least32_t uint_least32_t int_least64_t uint_least64_t int_fast8_t uint_fast8_t int_fast16_t uint_fast16_t int_fast32_t uint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong atomic_wchar_t atomic_char16_t atomic_char32_t atomic_intmax_t atomic_uintmax_t atomic_intptr_t atomic_uintptr_t atomic_size_t atomic_ptrdiff_t atomic_int_least8_t atomic_int_least16_t atomic_int_least32_t atomic_int_least64_t atomic_uint_least8_t atomic_uint_least16_t atomic_uint_least32_t atomic_uint_least64_t atomic_int_fast8_t atomic_int_fast16_t atomic_int_fast32_t atomic_int_fast64_t atomic_uint_fast8_t atomic_uint_fast16_t atomic_uint_fast32_t atomic_uint_fast64_t",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c","cc","h","c++","h++","hpp"],k:i,i:"</",c:[t.CLCM,t.CBCM,t.QSM,{cN:"string",b:"'\\\\?.",e:"'",i:"."},{cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},t.CNM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line pragma",c:[{b:/\\\n/,r:0},{b:'include\\s*[<"]',e:'[>"]',k:"include",i:"\\n"},t.CLCM]},{b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:i,c:["self"]},{b:t.IR+"::",k:i},{bK:"new throw return else",r:0},{cN:"function",b:"("+t.IR+"\\s+)+"+t.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:i,c:[{b:t.IR+"\\s*\\(",rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:i,r:0,c:[t.CBCM]},t.CLCM,t.CBCM]}]}});

window.onload = function()
{
	/* force all code elements to be C++ */
    var code_elements = document.getElementsByTagName("code");
    for(var i=0; i<code_elements.length; ++i)
    {
	    code_elements[i].className = 'cpp';
    }

    hljs.initHighlighting();
}
</script>

</head>
<body>

  <h1>Smart Objects, an alternative approach to overloading operator dot</h1>

<div id="info">

<div id="docinfo">
  <table border="1">
    <tr> <th>Doc. No.:</th> <td>N4495</td> </tr>
    <tr> <th>Date:</th>     <td>2015-05-22</td> </tr>
    <tr> <th>Project:</th>  <td>Programming Language C++, Evolution Working Group</td> </tr>
    <tr> <th>Reply To:</th> <td>Mathias Gaunard &lt;<a href="mailto:mathias@gaunard.com">mathias@gaunard.com</a>&gt;,<br>
                                Dietmar Kühl &lt;<a href="mailto:dkuhl@bloomberg.net">dkuhl@bloomberg.net</a>&gt;</td> </tr>
  </table>
  </div>

<div id="toc">
<p>Table of Contents:</p>
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#design-and-specification">Design and Specification</a><ul>
<li><a href="#lookup-rules">Lookup rules</a></li>
<li><a href="#member-functions-and-scope-capture">Member functions and scope capture</a></li>
<li><a href="#extension-to-reflection">Extension to reflection</a></li>
</ul></li>
<li><a href="#properties-of-the-design">Properties of the Design</a><ul>
<li><a href="#controlling-reference-leaking">Controlling reference leaking</a></li>
<li><a href="#overloading-operator.-on-multiple-objects">Overloading operator.() on multiple objects</a></li>
<li><a href="#sfinae-on-the-synthesized-function-object">SFINAE on the synthesized function object</a></li>
<li><a href="#no-handling-of-static-members">No handling of static members</a></li>
<li><a href="#repeated-evaluation-and-move-semantics">Repeated evaluation and move semantics</a></li>
</ul></li>
<li><a href="#examples-and-use-cases">Examples and Use Cases</a><ul>
<li><a href="#polymorphic-value-types">Polymorphic Value Types</a></li>
<li><a href="#sum-types">Sum Types</a></li>
<li><a href="#dynamic-duck-typing">Dynamic Duck Typing</a></li>
<li><a href="#expression-templates">Expression Templates</a></li>
<li><a href="#dynamic-properties-reflection-extension">Dynamic Properties (reflection extension)</a></li>
<li><a href="#vector-of-values">Vector of values</a></li>
</ul></li>
</ul>
</div>

</div>

<div id="body">
<h2 id="introduction"><a href="#introduction">Introduction</a></h2>
<p>This proposal suggests an approach to allow overloading the dot operator that is an alternative to the solution proposed in <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a>. It is based on <strong>having the compiler synthesize a function object</strong> whenever a call to that operator is made rather than return a user-defined reference.</p>
<p>This approach can do everything that <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a> can while avoiding some of its issues. The approach also allows some novel uses which are described below.</p>
<h2 id="motivation"><a href="#motivation">Motivation</a></h2>
<p>The advent of smart pointers, types making use of the capacity to overload the arrow (<code>-&gt;</code>) operator to mimic pointers while providing extra behaviour like automatic lifetime management, has only highlighted the lack of having the ability to overload the dot (<code>.</code>) operator to achieve smart references, or better yet, smart objects.</p>
<p>In the following proposal, we will use the terminology <em>smart reference</em> to refer to a use case that is possible with both this proposal and <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a>, and <em>smart object</em> for a use case that requires the method presented in this proposal.</p>
<p>Examples of <em>smart references</em> include:</p>
<ul>
<li><strong>Smart pointers that are really references</strong>: smart pointer-like objects that have reference semantics rather than pointer semantics.</li>
<li><strong>Proxies</strong>: objects that must intercept every call to a member before rerouting it to some other object.</li>
<li><strong>Interface refinement</strong>: build new objects by composing existing objects, forwarding to them, and adding new members.</li>
<li><strong>Pimpl and handles</strong>: making an indirection to another private object transparent without having to forward every member value or function.</li>
</ul>
<p>Examples of <em>smart objects</em> include:</p>
<ul>
<li><strong>Sum types aka variants</strong>: objects that can hold values of different types. It is possible to define operator dot so that it forwards to the members of the actual type contained.</li>
<li><strong>Duck typing</strong>: similar to sum types, but the error of not having a particular member function for a given type is delayed to when the binding to the actual value occurs.</li>
<li><strong>Expression templates and DSELs</strong>: building a type that allows delayed evaluation by building an object representing the call rather than evaluating it is very useful to build <em>Domain-Specific Embedded Languages</em> that are based on the famous expression templates technique.</li>
<li><strong>Aggregates of key-value pairs</strong>: objects that are aggregates of runtime-defined properties could be accessed through operator dot instead of an explicit string.</li>
<li><strong>Repeated evaluation</strong>: objects that do not forward the member access to a single object but to several objects in succession.</li>
</ul>
<p>Additionally, the function object approach allows fine control of what is forwarded, under what condition, and in what order. The discussed below provides more details.</p>
<h2 id="design-and-specification"><a href="#design-and-specification">Design and Specification</a></h2>
<h3 id="lookup-rules"><a href="#lookup-rules">Lookup rules</a></h3>
<p>When looking up a non-static member of a user-defined-type, if no member by the name requested exists, and the type has a declaration of a non-static member function named <code>operator.</code> with matching cv-qualifiers, then the compiler shall synthesize a function object with a <code>operator()</code> member function template taking an arbitrary object as parameter and applying the name to it. An instance of that synthesized function object is passsed as argument to the <code>operator.</code> member function.</p>
<p>For example, <code>x.some_name;</code> gets translated into <code>x.operator.(synthesized_function_type{});</code> where <code>x.some_name</code> wouldn't otherwise be found.</p>
<p>In this case, the synthesized function type could be equivalent to the following:</p>
<pre><code>struct synthesized_function_type {
    template&lt;class T&gt;
    auto operator()(T&amp;&amp; t) -&gt; decltype(t.some_name) noexcept(t.some_name) {
        return t.some_name;
    }
};</code></pre>
<p>Special capture behavior for calls to member functions is decribed in the next section.</p>
<h3 id="member-functions-and-scope-capture"><a href="#member-functions-and-scope-capture">Member functions and scope capture</a></h3>
<p>If the compiler must synthesize a function object for a member function call, each subexpression evaluating each argument shall be evaluated prior to constructing the synthesized function object. Rvalue-ness shall be forwarded correctly, with rvalues held by value and lvalues by reference.</p>
<p>For example, the calls <code>x.some_name(a, foo(), foo())</code> shall get translated to to <code>x.operator.(synthesized_function_type{a, foo(), foo()});</code> where the synthesized function type could be equivalent to the following:</p>
<pre><code>struct synthesized_function_type {
    // `a&#39; or `foo&#39; may not be visible in that context
    // used here lexically just for demonstration purposes
    typedef decltype((a)) T0;
    typedef decltype(foo()) T1;
    typedef decltype(foo()) T2;
    T0 a0;
    T1 a1;
    T2 a2;

    template&lt;class T&gt;
    auto operator()(T&amp;&amp; t) -&gt; decltype(t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2))) noexcept(t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2))) {
        return t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2));
    }
};</code></pre>
<p>The construction of the <code>synthesized_function_type</code> or the initialization of any of the members can be elided as long as calls to the function call operator can be made with the appropriate arguments. In particular, if the compiler can determine that a use of <code>operator.()</code> results in a member function call on a specific object it can elide construction of the function object and replace a call to its function call operator with a direct call to the member function.</p>
<h3 id="extension-to-reflection"><a href="#extension-to-reflection">Extension to reflection</a></h3>
<p>The mechanism could optionally be extended to support <strong>reflection</strong> by adding arbitrary extra information within the synthesized function object type.</p>
<p>Further work will be done in that area in future versions of the proposal depending on feedback.</p>
<p>For example for member variables:</p>
<pre><code>struct synthesized_function_type {
    template&lt;class T&gt;
    auto operator()(T&amp;&amp; t) -&gt; decltype(t.some_name) noexcept(t.some_name) {
        return t.some_name;
    }

    static constexpr const char* name() { return &quot;some_name&quot;; }
    static constexpr bool is_member_function = false;
};</code></pre>
<p>For member functions:</p>
<pre><code>struct synthesized_function_type {
    // `a&#39; or `foo&#39; may not be visible in that context
    // used here lexically just for demonstration purposes
    typedef decltype((a)) T0;
    typedef decltype(foo()) T1;
    typedef decltype(foo()) T2;
    T0 a0;
    T1 a1;
    T2 a2;

    template&lt;class T&gt;
    auto operator()(T&amp;&amp; t) -&gt; decltype(t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2))) noexcept(t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2))) {
        return t.t.some_name(static_cast&lt;T0&amp;&amp;&gt;(a0), static_cast&lt;T1&amp;&amp;&gt;(a1), static_cast&lt;T2&amp;&amp;&gt;(a2));
    }

    static constexpr const char* name() { return &quot;some_name&quot;; }
    static constexpr bool is_member_function = true;
    typedef std::tuple&lt;T0, T1, T2&gt; member_arguments;
};</code></pre>
<h2 id="properties-of-the-design"><a href="#properties-of-the-design">Properties of the Design</a></h2>
<h3 id="controlling-reference-leaking"><a href="#controlling-reference-leaking">Controlling reference leaking</a></h3>
<p><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a> discusses <em>reference leaking</em> in section 5: the possibility that <code>operator.()</code> can reult in functions accidentally returning a reference to an object held by a smart reference. Since N4477 proposes the implementation of <code>operator.()</code> in similar ways as <code>operator-&gt;()</code> but returning a reference rather than a pointer the control of the returned reference needs to be in the language.</p>
<p>When implementing <code>operator.()</code> in terms of a passed function object the implementer of a smart reference has full control over the type returned from <code>operator.()</code>. In its simplest form reference leaking can be prevented by not returning anything from the resulting operator:</p>
<pre><code>class strictly_non_leaking {
    X x;
public:
    template &lt;typename Fun&gt;
    auto operator.(Fun&amp;&amp; fun) -&gt; void { fun(x); }
};</code></pre>
<p>While that may be viable for some smart reference types, most smart reference would probably want to return a suitable result. It would be straight forward to prevent certain known return types, e.g., by conditionally wrapping results into a suitable type:</p>
<pre><code>class wrapping {
    X x;
public:
    wrapping(X&amp; ref);
    template &lt;typename Fun&gt;
    auto operator.(Fun&amp;&amp; fun)
        -&gt; std::condition_t&lt;std::is_same_v&lt;X&amp;, decltype(fun(std::declval&lt;X&amp;&gt;()))&gt;,
                            wrapping, decltype(fun(std::declval&lt;X&amp;&gt;()))&gt; {
        return fun(x);
    }
};</code></pre>
<p>What exactly a smart reference returns from a use can be controlled by the smart reference. In particular the good (<code>incr(x)</code>) case can be supported while the bad (<code>leak(x)</code>) case can be banned.</p>
<h3 id="overloading-operator.-on-multiple-objects"><a href="#overloading-operator.-on-multiple-objects">Overloading operator.() on multiple objects</a></h3>
<p><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a> discusses overloading <code>operator.()</code> in section 4.9. While there it is obvious that operator.() can be overloaded for cv-qualified version and reference qualifications, N4477 also proposes to overload on the reference type returned from <code>operator.()</code>. The idea is that multiple version of <code>operator.()</code> can be used to return different reference types and the unique version applicable for a member use is chosen. The choice of <code>operator.()</code> based on the reference type is similar to the choice made when finding a member function in a class with multiple base classes: if a unique match is found it is chosen otherwise (if there are no or multiple matches) the use is an error.</p>
<p>When passing a function objcet to <code>operator.()</code> this form of overloading isn't possible. However, such special overloading rules are not needed as the same effect can be achieved by determining if a function call can be made:</p>
<pre><code>class composite {
    A a;
    B b;
public:
    template &lt;typename Fun&gt;
    auto operator.(Fun&amp;&amp; fun)
        -&gt; decltype(call_unique(std::forward&lt;Fun&gt;(fun), std::tie(this-&gt;a, this-&gt;b))) {
        return call_unique(std::forward&lt;Fun&gt;(fun), std::tie(this-&gt;a, this-&gt;b));
    }
};</code></pre>
<p>The function <code>call_unique()</code> determines if there is exactly one element <code>x</code> in the passed <code>std::tuple&lt;...&gt;</code> for which <code>fun(x)</code> is a valid called and, if so, returns the result of calling <code>fun</code> with this element. Otherwise, it produces an error. This function isn't easy to write but it could be made available by the standard library to aid with common choices. Since it is a library function other choices could be made, however. For example, instead of calling the unique choice a different approach could be to call the first match.</p>
<h3 id="sfinae-on-the-synthesized-function-object"><a href="#sfinae-on-the-synthesized-function-object">SFINAE on the synthesized function object</a></h3>
<p>A lot of advanced uses of overloading <code>operator.</code> with the scheme described on this proposal rely on SFINAE extended for expressions. SFINAE for expressions is necessary to be able to tell whether a member exists for a particular object, i.e., whether the synthesized function object can be called with a specific parameter type.</p>
<p>This is why the signature of the <code>operator()</code> member function template of the synthesized function objects has a return type defined with <code>decltype</code> rather than just relying on a specification using <code>auto</code> or <code>decltype(auto)</code>.</p>
<h3 id="no-handling-of-static-members"><a href="#no-handling-of-static-members">No handling of static members</a></h3>
<p>To build perfect smart references or proxies, it would not only be required to forward regular members, but static ones as well. For example, consider a proxy for <code>std::vector</code> which should have the <code>::iterator</code> be provided, too.</p>
<p>Like <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a>, the proposal currently doesn't cover static members. The mechanism could be extended to support these members. The main issue is being able to deal with both types and values, in particular in contexts where member types are not annotated with <code>typename</code>.</p>
<h3 id="repeated-evaluation-and-move-semantics"><a href="#repeated-evaluation-and-move-semantics">Repeated evaluation and move semantics</a></h3>
<p>The synthesized function call operator forwards arguments when it is called. As a result rvalue arguments get moved by the first call to the function call operator. For typical uses cases where the member access is forwarded to another object this behavior is exactly what is desired. Since the function call operator on the argument passed to <code>operator.</code> could easily be called multiple times, subsequent calls to the function call operator would call the member access with already moved from arguments. This behavior is similar to using multiple move operations on the same object, though.</p>
<p>For some of the use cases described below repeated calls to the function call operator are desirable. Ideally the captured arguments could be forwarded appropriately. However, since the synthesized function entirely encapsulates the presence and processing of the arguments there is no way to specify whether arguments should be moved if there is just one function call operator with the argument on which member is applied. It would be possible to provide another way to invoke the funciton which wouldn't move, e.g., by passing a second argument or by calling a named function.</p>
<h2 id="examples-and-use-cases"><a href="#examples-and-use-cases">Examples and Use Cases</a></h2>
<h3 id="polymorphic-value-types"><a href="#polymorphic-value-types">Polymorphic Value Types</a></h3>
<p>Inheritance and subtyping polymorphism is a use case for some sort of dynamic typing. If given a base class <code>Base</code>, and several derived classes <code>Derived1</code>, <code>Derived2</code> or <code>Derivedn</code>, it is often useful to be able to have an object that can contain any of the <code>Derivedi</code> classes derived from <code>Base</code>.</p>
<p>Smart pointers are a popular solutions to this problem. While smart pointers provide an entity semantic, there is also an argument that can be made for having value semantics instead, where copies actually copies the data instead of aliasing it.</p>
<p>This copying can be achieved using a special smart pointer. There are several implementations of this approach on the Internet under the name <code>clone_ptr</code>. Pointer syntax is however not very appropriate when providing someting using value semantics. An object an example of what it could look like with this proposal. Let's name the type that can hold any type derived from <code>T</code> while providing a value semantic <code>poly&lt;T&gt;</code>, below is a simplistic implementation relying on an intrusive &quot;clone&quot; virtual member function and lacking move semantics and other fancy features.</p>
<pre><code>template&lt;class T&gt;
struct poly {
    poly(T const&amp; t) : ptr(new T(t)) {}
    ~poly() { delete ptr; }

    poly(const poly&amp; other) ptr(other.p-&gt;clone()) {}

    poly&amp; operator=(poly other) {
        std::swap(ptr, other.ptr);
        return *this;
    }

    template&lt;class F&gt;
    decltype(auto) operator.(F f) {
        return f(*ptr);
    }

    template&lt;class F&gt;
    decltype(auto) operator.(F f) const {
        return f(*ptr);
    }

private:
    T* ptr;
};</code></pre>
<p>It then becomes possible to write things like this:</p>
<pre><code>poly&lt;Base&gt; obj = Derived1();
a.virtual_member_function_of_Base();
a = Derived2();
int x = a.member_variable_of_Base;</code></pre>
<h3 id="sum-types"><a href="#sum-types">Sum Types</a></h3>
<p>Sum types, also called tagged unions or variants, are data structures that can hold an object of either of a list of possibly unrelated types. Proposal <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4450.pdf">N4450</a> suggests adding such a type to the standard library, named <code>variant</code>, based on the <code>boost::variant</code> class template.</p>
<p>Proposal <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4450.pdf">N4450</a> for the variant type provides very limited operator overloading (only <code>&lt;</code>, <code>&lt;=</code>, <code>=</code>, <code>!=</code>, <code>&gt;=</code> and <code>&gt;</code>), but a case could be made for providing overloading for all operators, including operator dot. This raises a couple of interesting questions regarding what the result type of that operator should be, and whether a hard error should be emitted if the operator in question is not available on one or more of the types in the set.</p>
<p>For the use case below, we present a partial interface of a simple variant implementation with freestore-based storage and pseudo-code to ignore some of the implementation complications inherent to variant. Operator dot returns the common type of all possible cases, and the operator being called must be valid for all cases.</p>
<pre><code>template&lt;class... T&gt;
struct variant {
    template&lt;class U&gt;
    variant(U const&amp; u) : ptr(new U(u)), which(find_offset&lt;seq&lt;T...&gt;, U&gt;::value) {}

    ~variant() { type_erased_delete(ptr); }

    variant(variant const&amp; other) : ptr(type_erased_clone(other)), which(other.which) {}

    variant&amp; operator=(variant other) {
        swap(ptr, other.ptr);
        swap(which, other.which);
        return *this;
    }

    template&lt;class F&gt;
    decltype(auto) operator.(F f) {
        switch(which)
        {
            case 0: return f(*static_cast&lt;T0*&gt;(ptr));
            case 1: return f(*static_cast&lt;T1*&gt;(ptr));
            /* for every Ti... */
        }
    }

    template&lt;class F&gt;
    decltype(auto) operator.(F f) const {
        switch(which)
        {
            case 0: return f(*static_cast&lt;T0 const*&gt;(ptr));
            case 1: return f(*static_cast&lt;T1 const*&gt;(ptr));
            /* for every Ti... */
        }
    }

private:
    void* ptr;
    int which;
};</code></pre>
<p>This use case is a prime example of a smart object. This interface can be achieved by synthesizing a function object but it cannot be achieved by forwarding to a reference like in N4477 (operator dot), since there is no reference to a single object that variant could return.</p>
<p>It becomes possible to write things like this:</p>
<pre><code>struct Foo { const char* name() { return &quot;Foo&quot;; } };
struct Bar { const char* name() { return &quot;Bar&quot;; } void bark() { cout &lt;&lt; name() &lt;&lt; endl; } };

variant&lt;Foo, Bar&gt; v = Foo();
v = Bar();
const char* s = v.name();
//v.bark(); // error: not all types define &#39;bark&#39;</code></pre>
<h3 id="dynamic-duck-typing"><a href="#dynamic-duck-typing">Dynamic Duck Typing</a></h3>
<p>Duck typing is a technique which involves binding a name to an object as lately as possible: if the name is available at the time it is needed, call it, otherwise raise an error. Most dynamic typed language are based on this principle as it provides a very easy and flexible programming model.</p>
<p>It cannot be implemented in C++ generally, but it is possible to provide duck typing over a finite set of types, so it is possible to provide it for a variant type like above. It requires being able to test at compile-time if a given type satisfies the call, in order to be able to fallback to code that generates an error in case the expression is not supported.</p>
<p>This is one use case that requires the synthesized function object to contain its full body in its signature, so that it can be used in SFINAE contexts.</p>
<p>From a synthesized function object for the operator dot call, the implementation would wrap it in another function object with a fallback by doing something like this:</p>
<pre><code>template&lt;class T, class R = void&gt;
struct sink { typedef R type; };

template&lt;class Sig, class Enable = void&gt;
struct is_callable : std::false_type {};

template&lt;class F, class... Args&gt;
struct is_callable&lt;F(Args...), typename sink&lt;decltype(std::declval&lt;F&gt;()(std::declval&lt;Args&gt;()...))&gt;::type&gt; : std::true_type {};

template&lt;class F, class R&gt;
struct call_or_throw : F {
    using F::operator();

    template&lt;class T&gt;
    typename std::enable_if&lt;!is_callable&lt;F(T&amp;&amp;)&gt;::value, R&gt;::type operator()(T&amp;&amp; t) const
    {
        throw std::runtime_error(&quot;No such operation&quot;);
    }
};</code></pre>
<p>The operator. overload now looks like this:</p>
<pre><code>template&lt;class... T&gt;
struct duck_variant {
    /* content from variant... */

    template&lt;class F&gt;
    decltype(auto) operator.(F f) {
        switch(which)
        {
            case 0: return call_or_throw{f}(*static_cast&lt;T0*&gt;(ptr));
            case 1: return call_or_throw{f}f(*static_cast&lt;T1*&gt;(ptr));
            /* for every Ti... */
        }
    }
};</code></pre>
<p>It becomes possible to write things like this:</p>
<pre><code>struct Foo { const char* name() { return &quot;Foo&quot;; } };
struct Bar { const char* name() { return &quot;Bar&quot;; } void bark() { cout &lt;&lt; name() &lt;&lt; endl; } };

duck_variant&lt;Foo, Bar&gt; v = Foo();
v = Bar();
const char* s = v.name();
v.bark(); // correct even if Foo has no &#39;bark&#39;</code></pre>
<h3 id="expression-templates"><a href="#expression-templates">Expression Templates</a></h3>
<p>Expression templates is a mechanism using operator overloading to delay evaluations of expressions and then evaluate them with a given context, which enables building entire Domain-Specific Languages embedded into C++. For this use case, forwarding to a reference is not possible, and generating a function object fits exactly the needs of delaying evaluation that is needed.</p>
<p>In this case, the <code>operator.</code> would just return the synthesized function object or more likely a wrapper of that function object.</p>
<h3 id="dynamic-properties-reflection-extension"><a href="#dynamic-properties-reflection-extension">Dynamic Properties (reflection extension)</a></h3>
<p>Another use case where overloading the dot operator is useful is for objects where the member names are dynamic, like those obtained from binding to a dynamic language, serialization to XML or JSON, or anything deciding fields at runtime. This cannot be addressed by just providing a function object, but it is trivial to extend the function objects to contain additional information to support that use case. With N4477 (operator dot), there is no obvious way to extend the mechanism to support this use case.</p>
<p>Assuming the synthesized function object is augmented to support reflection, i.e., a <code>name()</code> function return the name of the member being applied, it could therefore look like this:</p>
<pre><code>struct Value {
    Value() : data(Map()) {}
    Value(int i) : data(i) {}
    Value(double d) : data(d) {}
    Value(std::string const&amp; s) : data(s) {}

    template&lt;class F&gt;
    Value&amp; operator.(F f) {
        return get&lt;Map&gt;(data)[F::name()];
    }

    template&lt;class F&gt;
    Value const&amp; operator.(F f) const {
        return get&lt;Map&gt;(data)[F::name()];
    }

private:
    typedef std::unordered_map&lt;std::string, Value&gt; Map;
    variant&lt;Map, int, double, std::string&gt; data;
}</code></pre>
<p>And this would allow the following usage:</p>
<pre><code>Value v;
v.foo = 42;
v.bar = &quot;bar&quot;;</code></pre>
<p>Adding &quot;foo&quot; and &quot;bar&quot; members dynamically.</p>
<h3 id="vector-of-values"><a href="#vector-of-values">Vector of values</a></h3>
<p>Just like <code>+</code> on <code>std::valarray</code> adds all of its values, it could also be interesting to call a member on all the values of the vector as well. Consider <code>valarray&lt; complex&lt;T&gt; &gt;</code>, it would be useful to be able to apply <code>.real()</code> and <code>.imag()</code> to all members of the vector at once without requiring special specialization.</p>
<p>This is a use case that requires calling the function object several times on different values, and that isn't supported by forwarding it to a single reference like in <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4477.pdf">N4477</a>.</p>
<pre><code>template&lt;class T&gt;
struct array {
    template&lt;class F&gt;
    auto operator.(F f) -&gt; array&lt; decltype(f(values[0])) &gt; {
        array&lt; decltype(f(values[0])) &gt; result(values.size());
        for(size_t i=0; i&lt;values.size(); ++i)
            result[i] = f(values[i]);
        }
        return result;
    }

private:
    std::vector&lt;T&gt; values;
};</code></pre>
</div>

</body>
</html>