220 6060 <c354d976-77e3-47a3-ac8c-6a3b0ea15bbf@isocpp.org> article
Path: news.gmane.org!not-for-mail
From: Artyom Lebedev <artyom.lebedev@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Templates usage with *this
Date: Sun, 1 Sep 2013 00:23:44 -0700 (PDT)
Lines: 391
Approved: news@gmane.org
Message-ID: <c354d976-77e3-47a3-ac8c-6a3b0ea15bbf@isocpp.org>
References: <e0049c1d-1b02-42bc-a871-2f5749572c41@isocpp.org>
 <e41ce277-f6f9-4dbe-92f7-dc8510efb6d3@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_652_7857596.1378020224195"
X-Trace: ger.gmane.org 1378020229 12321 80.91.229.3 (1 Sep 2013 07:23:49 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Sun, 1 Sep 2013 07:23:49 +0000 (UTC)
To: std-proposals@isocpp.org
Original-X-From: std-proposals+bncBC4KXOVK3ENRBAGXROIQKGQEJY7J76I@isocpp.org Sun Sep 01 09:23:51 2013
Return-path: <std-proposals+bncBC4KXOVK3ENRBAGXROIQKGQEJY7J76I@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-qe0-f71.google.com ([209.85.128.71])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBC4KXOVK3ENRBAGXROIQKGQEJY7J76I@isocpp.org>)
	id 1VG20g-00034n-TY
	for gclcip-std-proposals@m.gmane.org; Sun, 01 Sep 2013 09:23:47 +0200
Original-Received: by mail-qe0-f71.google.com with SMTP id 1sf4085639qee.10
        for <gclcip-std-proposals@m.gmane.org>; Sun, 01 Sep 2013 00:23:45 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20120113;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe
         :content-type;
        bh=ilJ8wSMzl+hh0Sc7HvXl7sHWu4mhgy838Z6jEz47Q/s=;
        b=IVT635ZvFYR6xCBcmwJ6vYd9vhiDkcQsKH1aM25y45iCriFgBVaAQwY/OxOgL5sI0z
         XOpXZoIeP/ZBA9i1P/uqwFRjxOYBXxExNE9VvGFZ/l22cFgykmzTD1keeIRPXwLrwRoN
         ZnjTHr3IVU47Vu/3nz5vdARITWhCTGiZP2lttFpuiijwHfDHaAHDFJ5J4+kyovEyWsBA
         /I74YCRHn8zsXY0AFEd4vrNBsZohRRQ9EwdUpdZulq0I4xUR6I4orDk0htAc2e6Bzz3z
         LBUv/BWHSQR5pmT0AR4/87w2Yd0QtHXK4aCZYDmJHJipgy6Pa4lyJ/SyE8OfOA/4JlBV
         ptqA==
X-Received: by 10.236.19.225 with SMTP id n61mr6059349yhn.8.1378020225132;
        Sun, 01 Sep 2013 00:23:45 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.49.82.114 with SMTP id h18ls1781915qey.12.gmail; Sun, 01 Sep
 2013 00:23:44 -0700 (PDT)
X-Received: by 10.49.14.170 with SMTP id q10mr656588qec.5.1378020224565;
        Sun, 01 Sep 2013 00:23:44 -0700 (PDT)
In-Reply-To: <e41ce277-f6f9-4dbe-92f7-dc8510efb6d3@isocpp.org>
X-Original-Sender: artyom.lebedev@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <http://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <http://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <http://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:6060
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/6060>

------=_Part_652_7857596.1378020224195
Content-Type: text/plain; charset=ISO-8859-1


>
> Standard disclaimer: accessor functions are evil. C++ has a perfectly good 
> model for accessing members; do not roll your own unless you legitimately 
> have a custom object model.
>
Probably you a bit misunderstood the idea. It by no means related to 
accessor functions. May be you were confused by my first example with Get() 
method name and Maurice example provided by link where he returns data 
member in his method. So I will provide another example for better 
understanding of use cases.

Let's say we have a class which represents some path in a filesystem (or in 
any hierarchical data structure). Path is stored as its components (strings 
between separators) list. It might be std::list<std::string> or 
std::vector<std::string>. The class has two versions of Slice() method 
which returns arbitrary part of the path defined by start components index 
and number of components (like substr()). The version for "*this" = "const 
ClassType &" creates a new list with copies of necessary component strings. 
The version for "*this" = "ClassType &&"can be optimized a lot - it does 
not allocate or copy anything, instead it trims existing list as necessary 
and moves it to the returned result. So far it is well done with existing 
functionality. Now let's say you also have methods DirName() and BaseName() 
which should return path part before the last component and last component 
only. Obviously, they can use slice method, but because of the subject 
feature lack, you will need to define several versions for them with the 
same algorithm inside - the typical use case for templates. The code:

class Path {
private:
    std::vector<std::string> components;

    Path(std::vector<std::string> &&components):
        components(components)
    {}
public:
    //version for lvalue
    Path
    Slice(size_t start, size_t count) const &
    {
        //create new components list
        std::vector<std::string> slice;
        //populate it with necessary components
        ...
        return Path(std::move(slice));
    }

    //version for rvalue
    Path
    Slice(size_t start, size_t count) &&
    {
        //just trim unnecessary components from own list
        if (start != 0) {
            components.erase(components.begin(), components.begin() + 
start);
        }
        components.resize(count);
        //return this object as the result
        return std::move(*this);
    }

    //This is full of copy-paste current approach
    Path
    BaseName() const &
    {
        if (components.empty()) {
            return Path();
        }
        return Slice(components.size() - 1, components.size());
    }

    Path
    BaseName() &&
    {
        if (components.empty()) {
            return std::move(*this);
        }
        return std::move(*this).Slice(components.size() - 1, 
components.size());
    }

    Path
    DirName() const &
    {
        if (components.empty()) {
            return Path();
        }
        return Slice(0, components.size() - 1);
    }

    Path
    DirName() &&
    {
        if (components.empty()) {
            return std::move(*this);
        }
        return std::move(*this).Slice(0, components.size() - 1);
    }

    //And this the proposed one
    template <this PathType>
    PathType
    BaseName() &&
    {
        if (components.empty()) {
            return std::forward<PathType>(*this);
        }
        return std::forward<PathType>(*this).Slice(components.size() - 1, 
components.size());
    }

    template <this PathType>
    Path
    DirName() &&
    {
        if (components.empty()) {
            return std::forward<PathType>(*this);
        }
        return std::forward<PathType>(*this).Slice(0, components.size() - 
1);
    }
};

I hope this example is much more clear. In general, the idea is that now we 
have full set of qualifiers for "*this", just like for any other argument, 
but lack possibility to make its type templatized, like any other argument. 
In my opinion, it would be very logically, and now it looks like unfinished 
solution. And, as illustrated by the examples, there are real use cases for 
that.

You can't get the actual type of the argument which initialized *this; as 
> noted only templates can represent simultaneous types and otherwise you 
> have all the combinations of cv-qualification and value category.
>
Yes, I fully understand this, and as I described in previous messages, we 
are interested only in proper match logic (e.g. lvalues not matched to 
rvalue ref) and deduced template type - just like with regular arguments 
and perfect forwarding pattern.

As you mentioned, const rvalue isn't actually used for anything, so the 
> const overload need not be ref-qualified. 

 Const qualifier is a bit special, in the meaning that rvalue is matched to 
"const T &". But do not forget about "volatile", there also might be use 
cases for it.

David Krauss:
>
> I must admit I didn't read your entire post.
>
> You can't get the actual type of the argument which initialized *this; as 
> noted only templates can represent simultaneous types and otherwise you 
> have all the combinations of cv-qualification and value category.
>
> What you can do is forgo a member function and use ADL and a non-member 
> function template with perfect forwarding regulated by SFINAE. This gets 
> you not only cv-qualification and value category but also the static type 
> from the call site.
>
> struct s {
>     int x;
>
>     template< typename self >
>     friend
>     typename std::enable_if< std::is_base_of< s, typename std::decay< self 
> >::type >::value,
>         std::decltype( std::declval< self >().x ) >::type
>     get_x( self && o )
>         { return std::forward< self >( o ).x; }
> };
>
> If I were you, though, I'd just elaborate the accessor functions as before 
> and delegate from the rvalue overload to the lvalue overload with an 
> explicit move. As you mentioned, const rvalue isn't actually used for 
> anything, so the const overload need not be ref-qualified. So the new 
> change doesn't effectively double the complexity, but in usual practice 
> only one new case is added, which essentially just forwards to an existing 
> case.
>
> (Standard disclaimer: accessor functions are evil. C++ has a perfectly 
> good model for accessing members; do not roll your own unless you 
> legitimately have a custom object model. It looks like OP here might.)
>

-- 

--- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_652_7857596.1378020224195
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-lef=
t: 1px solid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote">=
Standard disclaimer: accessor functions are evil. C++ has a perfectly=20
good model for accessing members; do not roll your own unless you=20
legitimately have a custom object model.<br></blockquote><div>Probably you =
a bit misunderstood the idea. It by no means related to accessor functions.=
 May be you were confused by my first example with Get() method name and Ma=
urice example provided by link where he returns data member in his method. =
So I will provide another example for better understanding of use cases.<br=
><br>Let's say we have a class which represents some path in a filesystem (=
or in any hierarchical data structure). Path is stored as its components (s=
trings between separators) list. It might be std::list&lt;std::string&gt; o=
r std::vector&lt;std::string&gt;. The class has two versions of Slice() met=
hod which returns arbitrary part of the path defined by start components in=
dex and number of components (like substr()). The version for "*this" =3D "=
const ClassType &amp;" creates a new list with copies of necessary componen=
t strings. The version for "*this" =3D "ClassType &amp;&amp;"can be optimiz=
ed a lot - it does not allocate or copy anything, instead it trims existing=
 list as necessary and moves it to the returned result. So far it is well d=
one with existing functionality. Now let's say you also have methods DirNam=
e() and BaseName() which should return path part before the last component =
and last component only. Obviously, they can use slice method, but because =
of the subject feature lack, you will need to define several versions for t=
hem with the same algorithm inside - the typical use case for templates. Th=
e code:<br><br><span style=3D"font-family: courier new,monospace;">class Pa=
th {<br>private:<br>&nbsp;&nbsp;&nbsp; std::vector&lt;std::string&gt; compo=
nents;<br><br>&nbsp;&nbsp;&nbsp; Path(std::vector&lt;std::string&gt; &amp;&=
amp;components):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; components(c=
omponents)<br>&nbsp;&nbsp;&nbsp; {}<br>public:<br>&nbsp;&nbsp;&nbsp; //vers=
ion for lvalue<br>&nbsp;&nbsp;&nbsp; Path<br>&nbsp;&nbsp;&nbsp; Slice(size_=
t start, size_t count) const &amp;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //create new components list<br>&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::vector&lt;std::string&gt; slice;<br>&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //populate it with necessary compone=
nts<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp; return Path(std::move(slice));<br>&nbsp;&nbsp;&nbs=
p; }<br><br>&nbsp;&nbsp;&nbsp; //version for rvalue<br>&nbsp;&nbsp;&nbsp; P=
ath<br>&nbsp;&nbsp;&nbsp; Slice(size_t start, size_t count) &amp;&amp;<br>&=
nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //just tr=
im unnecessary components from own list<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; if (start !=3D 0) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp; components.erase(components.begin(), components.b=
egin() + start);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; components.resize(count);<br>&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //return this object as the result<br>&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return std::move(*this);<br>&nbsp;&n=
bsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; //This is full of copy-paste current=
 approach<br>&nbsp;&nbsp;&nbsp; Path<br>&nbsp;&nbsp;&nbsp; BaseName() const=
 &amp;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
; if (components.empty()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp; return Path();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Slice(compo=
nents.size() - 1, components.size());<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;=
&nbsp;&nbsp; Path<br>&nbsp;&nbsp;&nbsp; BaseName() &amp;&amp;<br>&nbsp;&nbs=
p;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (components.emp=
ty()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; return std::move(*this);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }=
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return std::move(*this).Slic=
e(components.size() - 1, components.size());<br>&nbsp;&nbsp;&nbsp; }<br><br=
>&nbsp;&nbsp;&nbsp; Path<br>&nbsp;&nbsp;&nbsp; DirName() const &amp;<br>&nb=
sp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (compone=
nts.empty()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp; return Path();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br=
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Slice(0, components.size=
() - 1);<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; Path<br>&nbsp;&n=
bsp;&nbsp; DirName() &amp;&amp;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp; if (components.empty()) {<br>&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return std::move(*this);<br=
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp; return std::move(*this).Slice(0, components.size() - 1);<b=
r>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; //And this the proposed on=
e<br>&nbsp;&nbsp;&nbsp; template &lt;this PathType&gt;<br>&nbsp;&nbsp;&nbsp=
; PathType<br>&nbsp;&nbsp;&nbsp; BaseName() &amp;&amp;<br>&nbsp;&nbsp;&nbsp=
; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (components.empty()) {=
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retu=
rn std::forward&lt;PathType&gt;(*this);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return std::forw=
ard&lt;PathType&gt;(*this).Slice(components.size() - 1, components.size());=
<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; template &lt;this PathTy=
pe&gt;<br>&nbsp;&nbsp;&nbsp; Path<br>&nbsp;&nbsp;&nbsp; DirName() &amp;&amp=
;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if =
(components.empty()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; return std::forward&lt;PathType&gt;(*this);<br>&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp; return std::forward&lt;PathType&gt;(*this).Slice(0, components.size()=
 - 1);<br>&nbsp;&nbsp;&nbsp; }<br>};</span><br><br>I hope this example is m=
uch more clear. In general, the idea is that now we have full set of qualif=
iers for "*this", just like for any other argument, but lack possibility to=
 make its type templatized, like any other argument. In my opinion, it woul=
d be very logically, and now it looks like unfinished solution. And, as ill=
ustrated by the examples, there are real use cases for that.<br><br><blockq=
uote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 20=
4, 204); padding-left: 1ex;" class=3D"gmail_quote">You can't get the actual=
 type of the argument which initialized *this;=20
as noted only templates can represent simultaneous types and otherwise=20
you have all the combinations of cv-qualification and value category.<br></=
blockquote>Yes, I fully understand this, and as I described in previous mes=
sages, we are interested only in proper match logic (e.g. lvalues not match=
ed to rvalue ref) and deduced template type - just like with regular argume=
nts and perfect forwarding pattern.<br><br><blockquote style=3D"margin: 0px=
 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1e=
x;" class=3D"gmail_quote">As you mentioned, const rvalue isn't actually use=
d for anything, so the <span style=3D"font-family:courier new,monospace">co=
nst</span> overload need not be ref-qualified. </blockquote><div>&nbsp;Cons=
t qualifier is a bit special, in the meaning that rvalue is matched to "con=
st T &amp;". But do not forget about "volatile", there also might be use ca=
ses for it.<br></div><br></div>David Krauss:<blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div dir=3D"ltr">I must admit I didn't read your entire post.=
<br><br>You can't get the actual type of the argument which initialized *th=
is; as noted only templates can represent simultaneous types and otherwise =
you have all the combinations of cv-qualification and value category.<br><b=
r>What you can do is forgo a member function and use ADL and a non-member f=
unction template with perfect forwarding regulated by SFINAE. This gets you=
 not only cv-qualification and value category but also the static type from=
 the call site.<br><br><div style=3D"background-color:rgb(250,250,250);bord=
er-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:bre=
ak-word"><code><div><span style=3D"color:#008">struct</span><span style=3D"=
color:#000"> s </span><span style=3D"color:#660">{</span><span style=3D"col=
or:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">int</span><spa=
n style=3D"color:#000"> x</span><span style=3D"color:#660">;</span><span st=
yle=3D"color:#000"><br><br>&nbsp; &nbsp; </span><span style=3D"color:#008">=
template</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#=
000"> </span><span style=3D"color:#008">typename</span><span style=3D"color=
:#000"> </span><span style=3D"color:#008">self</span><span style=3D"color:#=
000"> </span><span style=3D"color:#660">&gt;</span><span style=3D"color:#00=
0"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">friend</span><span s=
tyle=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">typ=
ename</span><span style=3D"color:#000"> std</span><span style=3D"color:#660=
">::</span><span style=3D"color:#000">enable_if</span><span style=3D"color:=
#660">&lt;</span><span style=3D"color:#000"> std</span><span style=3D"color=
:#660">::</span><span style=3D"color:#000">is_base_of</span><span style=3D"=
color:#660">&lt;</span><span style=3D"color:#000"> s</span><span style=3D"c=
olor:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:=
#008">typename</span><span style=3D"color:#000"> std</span><span style=3D"c=
olor:#660">::</span><span style=3D"color:#000">decay</span><span style=3D"c=
olor:#660">&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#008">self</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">&gt;::</span><span style=3D"color:#000">type </span><span style=3D"c=
olor:#660">&gt;::</span><span style=3D"color:#000">value</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"><br>&nbsp; &nbsp; &nbsp;=
 &nbsp; std</span><span style=3D"color:#660">::</span><span style=3D"color:=
#008">decltype</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#000"> std</span><span style=3D"color:#660">::</span><span style=3D"color=
:#000">declval</span><span style=3D"color:#660">&lt;</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#008">self</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">&gt;().</span><span style=3D"co=
lor:#000">x </span><span style=3D"color:#660">)</span><span style=3D"color:=
#000"> </span><span style=3D"color:#660">&gt;::</span><span style=3D"color:=
#000">type<br>&nbsp; &nbsp; get_x</span><span style=3D"color:#660">(</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#008">self</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#660">&amp;&amp;</spa=
n><span style=3D"color:#000"> o </span><span style=3D"color:#660">)</span><=
span style=3D"color:#000"><br>&nbsp; &nbsp; &nbsp; &nbsp; </span><span styl=
e=3D"color:#660">{</span><span style=3D"color:#000"> </span><span style=3D"=
color:#008">return</span><span style=3D"color:#000"> std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">forward</span><span sty=
le=3D"color:#660">&lt;</span><span style=3D"color:#000"> </span><span style=
=3D"color:#008">self</span><span style=3D"color:#000"> </span><span style=
=3D"color:#660">&gt;(</span><span style=3D"color:#000"> o </span><span styl=
e=3D"color:#660">).</span><span style=3D"color:#000">x</span><span style=3D=
"color:#660">;</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#660">}</span><span style=3D"color:#000"><br></span><span style=3D"color:=
#660">};</span><span style=3D"color:#000"><br></span></div></code></div><br=
>If I were you, though, I'd just elaborate the accessor functions as before=
 and delegate from the rvalue overload to the lvalue overload with an expli=
cit <span style=3D"font-family:courier new,monospace">move</span>. As you m=
entioned, const rvalue isn't actually used for anything, so the <span style=
=3D"font-family:courier new,monospace">const</span> overload need not be re=
f-qualified. So the new change doesn't effectively double the complexity, b=
ut in usual practice only one new case is added, which essentially just for=
wards to an existing case.<br><br>(Standard disclaimer: accessor functions =
are evil. C++ has a perfectly good model for accessing members; do not roll=
 your own unless you legitimately have a custom object model. It looks like=
 OP here might.)<br></div></blockquote></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_652_7857596.1378020224195--

.
