Topic: Templates usage with *this
Author: artyom.lebedev@gmail.com
Date: Sat, 31 Aug 2013 01:25:54 -0700 (PDT)
Raw View
------=_Part_766_28935819.1377937554942
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
=20
Hi,
This in not a well-formed proposal but just my thoughts about the subject=
=20
feature. May be something similar is already planned but I did not find it=
=20
in C++14 features list.
So now, especially after introducing =93N2439 - Extending move semantics t=
o=20
*this=94, (*this) can be matched to differently qualified type:
class A {
void Method(); // 1. *this is "A&"
void Method() const; // 2. *this is "const A&"
void Method() volatile; // 3. *this is "volatile A&"
void Method() const volatile; // 4. *this is "const volatile A&"
void Method() &&; //5. matched to "A &&" but in scope of method=20
implementation *this is "A&" since it has name
void Method() const &&; //6. This one and similar CV+rvalue_ref, may be=
=20
not so meaningful in most cases but still worth to mention. *this is "const=
=20
A&", probably always matches "A&&".
};
Currently there is no way to create a method template, having type of=20
=93*this=94 as template parameter. In some cases you might want to have gen=
eric=20
implementation for a method and properly forward =93*this=94 to some other=
=20
function. The number of combinations for *this types reminds me the=20
situation with possible qualifiers for arguments in templates before=20
perfect forwarding pattern was introduced. Fortunately, now we have only=20
one problematic argument with dozen of choices (which were doubled after=20
N2439).
Small real world example of the applicable situation. Let's say I have a=
=20
class which encapsulates some value. The value has dynamic type, and may=20
have underlying type which requires heap allocation (e.g. string) so it is=
=20
perfect for moving. I have method Get<TargetType>() which returns the=20
value. The trick with the Get() method is that for =93rvalue *this=94 we ca=
n=20
move the stored value to the result returned to the caller (and this is=20
very cool language feature indeed).
class Value {
template <typename T>
T
Get() const &
{
// return a copy of the stored value
}
template <typename T>
T
Get() &&
{
// move the stored value to the returned result
}
// And here we might want to have some aliases
template <typename T>
operator T() const &
{
return Get<T>();
}
template <typename T>
operator T() &&
{
return std::move(*this).Get<T>();
}
template <typename T>
T
GetWithStuff() const &
{
return Get<T>() + Stuff<T>();
}
template <typename T>
T
GetWithStuff() &&
{
return std::move(*this).Get<T>() + Stuff<T>();
}
=20
};
The problem is that Get() method has some aliases (it might be another=20
method with just different name or some generalized additional logic, or,=
=20
for example, type casting operator). Did you also noticed copy-pasting=20
which naturally seems must be avoided? What I basically might want from the=
=20
language, is the ability to perfectly forward =93*this=94 to some functions=
..=20
Possible syntax (just the first idea):
template <this ThisType, typename T>
T
GetWithStuff() ThisType && //roughly equivalent to "T&&" in arguments when=
=20
using arguments forwarding
{
return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
}
I think =93this=94 keyword can be used in template parameters which is ver=
y=20
natural. Also I feel that all rules applicable to type deduction of=20
argument in =93T &&=94 form (in perfect forwarding pattern context), as wel=
l as=20
all rules for argument types and templates there, should be the same for=20
=93this=94 argument which is just written next to parenthesis. Thus such=20
construction
template <this ThisType, typename T>
T
GetWithStuff() const ThisType &
{
return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
}
will not have much sense (ThisType will be just =93Value=94) but still sho=
uld=20
work to make things consistent.
May be having template parameter name in =93*this=94 specification part is=
=20
redundant:
template <this ThisType, typename T>
T
GetWithStuff() const & //presence of "this" in template parameters=20
automatically applies it there
{
return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
}
Obviously =93this=94 can be used in template parameters for non-static cla=
ss=20
methods only.
IMHO such feature would be a nice addition for making the language even=20
more beautiful, and it should not be a problem to implement in compilers=20
since =93this=94 argument already should be implicitly present (with type=
=20
information) in most places, which are subject for the changes.
Best regards,
Artyom
--=20
---=20
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 e=
mail 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-proposa=
ls/.
------=_Part_766_28935819.1377937554942
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">
=09
=09
=09
<style type=3D"text/css">P { margin-bottom: 0.08in; }</style>
<p style=3D"margin-bottom: 0in">Hi,</p>
<p style=3D"margin-bottom: 0in">This in not a well-formed proposal but
just my thoughts about the subject feature. May be something similar is alr=
eady planned but I did not find it in C++14 features list.<br></p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">So now, especially after introducing
=93N2439 - Extending move semantics to *this=94, (*this) can be
matched to differently qualified type:</p><p style=3D"margin-bottom: 0in"><=
br></p>
<p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier new,mon=
ospace;">class A {</span></p><span style=3D"font-family: courier new,monosp=
ace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method(); // 1. *this is "A&"</=
span></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method() const; // 2. *this is "co=
nst A&"</span></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method() volatile; // 3. *this is =
"volatile A&"</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method() const volatile; // 4.
*this is "const volatile A&"</span></p><span style=3D"font-family: cour=
ier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method() &&; //5. matched
to "A &&" but in scope of method implementation *this is "A&" s=
ince it has name</span></p><span style=3D"font-family: courier new,monospac=
e;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> void Method() const &&; //6.
This one and similar CV+rvalue_ref, may be not so meaningful in most
cases but still worth to mention. *this is "const A&",
probably always matches "A&&".</span></p><span style=3D"font-family=
: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">};</span></p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">Currently there is no way to create a
method template, having type of =93*this=94 as template parameter. In
some cases you might want to have generic implementation for a method
and properly forward =93*this=94 to some other function. The number
of combinations for *this types reminds me the situation with
possible qualifiers for arguments in templates before perfect
forwarding pattern was introduced. Fortunately, now we have only one
problematic argument with dozen of choices (which were doubled after N2439)=
..</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">Small real world example of the applicable
situation. Let's say I have a class which encapsulates some value.
The value has dynamic type, and may have underlying type which
requires heap allocation (e.g. string) so it is perfect for moving. I
have method Get<TargetType>() which returns the value. The
trick with the Get() method is that for =93rvalue *this=94 we can
move the stored value to the result returned to the caller (and this is
very cool language feature indeed).</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier new,mon=
ospace;">class Value {</span></p><span style=3D"font-family: courier new,mo=
nospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> T</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> Get() const &</span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> // return a copy=
of the stored value</span></p><span style=3D"font-family: courier new,mono=
space;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> T</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> Get() &&</span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> // move the stor=
ed value to the returned
result</span></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> // And here we might want to have some
aliases</span></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> operator T() const &</span></p><span=
style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return Get<T&=
gt;();</span></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> operator T() &&</span></p><span =
style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return std::move=
(*this).Get<T>();</span></p><span style=3D"font-family: courier new,m=
onospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> T</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> GetWithStuff() const &</span></p><sp=
an style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return Get<T&=
gt;() + Stuff<T>();</span></p><span style=3D"font-family: courier new=
,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"><br></span>
</p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> template <typename T></span></p><s=
pan style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> T</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> GetWithStuff() &&</span></p><spa=
n style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> {</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return std::move=
(*this).Get<T>()
+ Stuff<T>();</span></p><span style=3D"font-family: courier new,monos=
pace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> }</span></p><span style=3D"font-family: =
courier new,monospace;">
</span><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">};</span></p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">The problem is that Get() method has
some aliases (it might be another method with just different name or
some generalized additional logic, or, for example, type casting
operator). Did you also noticed copy-pasting which naturally seems
must be avoided? What I basically might want from the language, is
the ability to perfectly forward =93*this=94 to some functions.
Possible syntax (just the first idea):</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier new,mon=
ospace;">template <this ThisType, typename T></span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">T</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">GetWithStuff() ThisType &&
//roughly equivalent to "T&&" in arguments when using
arguments forwarding</span></p><span style=3D"font-family: courier new,mono=
space;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">{</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">}</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">I think =93this=94 keyword can be used
in template parameters which is very natural. Also I feel that all
rules applicable to type deduction of argument in =93T &&=94
form (in perfect forwarding pattern context), as well as all rules
for argument types and templates there, should be the same for =93this=94
argument which is just written next to parenthesis. Thus such
construction</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier new,mon=
ospace;">template <this ThisType, typename T></span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">T</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">GetWithStuff() const ThisType &</span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">{</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">}</span></p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">will not have much sense (ThisType will
be just =93Value=94) but still should work to make things consistent.</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">May be having template parameter name
in =93*this=94 specification part is redundant:</p>
<p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier new,mon=
ospace;">template <this ThisType, typename T></span></p><span style=
=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">T</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">GetWithStuff() const & //presence
of "this" in template parameters automatically applies it there</span></p><=
span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">{</span></p><span style=3D"font-family: courier new,monospa=
ce;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;"> return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family: courier new,monospace;">
</span><p style=3D"margin-bottom: 0in"><span style=3D"font-family: courier =
new,monospace;">}</span></p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">Obviously =93this=94 can be used in
template parameters for non-static class methods only.</p>
<p style=3D"margin-bottom: 0in"><br>
</p>
<p style=3D"margin-bottom: 0in">IMHO such feature would be a nice
addition for making the language even more beautiful, and it should
not be a problem to implement in compilers since =93this=94 argument
already should be implicitly present (with type information) in most
places, which are subject for the changes.</p><p style=3D"margin-bottom: 0i=
n"><br></p><p style=3D"margin-bottom: 0in">Best regards,</p><p style=3D"mar=
gin-bottom: 0in">Artyom<br></p></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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_766_28935819.1377937554942--
.
Author: Maurice Bos <m-ou.se@m-ou.se>
Date: Sat, 31 Aug 2013 17:18:22 +0200
Raw View
--001a11336ce2c28b2704e53fdaf2
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
Hello,
I've been thinking about the same problem a few weeks ago. I was writing a
blog post about 'rvalue references for *this' (aka &&-member functions), in
which I also complained a bit about how annoying it is to define an
accessor properly (&, const &, &&, const &&, etc.) (
http://blog.m-ou.se/2013/07/21/rvalue-references-for-this.html). The
suggestion I gave had to 'fix' this, is similar to yours:
class foo {
std::string name_;
public:
decltype(auto) name() T && { return std::forward<T>(*this).name_; }
}:
However, there's one big difference with your solution: Here, foo::name()
is not a template. This syntax just and defines 8 different versions of
foo::name (the &, const &, volatile &, const volatile &, and all the &&
versions).
I'm not sure if it'd be better or not to make it a template (I haven't put
very much thought into it yet), but I just wanted to mention this option.
Also, there needs to be some way to specify you only want to define all the
& versions but not the && versions, or only the const versions. Something
like:
void whatever() T & { ... }
void whatever() T const { ... }
This would make repeating the template paramaeter name after the argument
list non-redundant in your template idea.
-Maurice-
2013/8/31 <artyom.lebedev@gmail.com>
> Hi,
>
> This in not a well-formed proposal but just my thoughts about the subject
> feature. May be something similar is already planned but I did not find i=
t
> in C++14 features list.
>
>
> So now, especially after introducing =93N2439 - Extending move semantics
> to *this=94, (*this) can be matched to differently qualified type:
>
>
> class A {
>
> void Method(); // 1. *this is "A&"
>
> void Method() const; // 2. *this is "const A&"
>
> void Method() volatile; // 3. *this is "volatile A&"
>
> void Method() const volatile; // 4. *this is "const volatile A&"
>
> void Method() &&; //5. matched to "A &&" but in scope of method
> implementation *this is "A&" since it has name
>
> void Method() const &&; //6. This one and similar CV+rvalue_ref, may
> be not so meaningful in most cases but still worth to mention. *this is
> "const A&", probably always matches "A&&".
>
> };
>
>
> Currently there is no way to create a method template, having type of
> =93*this=94 as template parameter. In some cases you might want to have g=
eneric
> implementation for a method and properly forward =93*this=94 to some othe=
r
> function. The number of combinations for *this types reminds me the
> situation with possible qualifiers for arguments in templates before
> perfect forwarding pattern was introduced. Fortunately, now we have only
> one problematic argument with dozen of choices (which were doubled after
> N2439).
>
>
> Small real world example of the applicable situation. Let's say I have a
> class which encapsulates some value. The value has dynamic type, and may
> have underlying type which requires heap allocation (e.g. string) so it i=
s
> perfect for moving. I have method Get<TargetType>() which returns the
> value. The trick with the Get() method is that for =93rvalue *this=94 we =
can
> move the stored value to the result returned to the caller (and this is
> very cool language feature indeed).
>
>
> class Value {
>
>
> template <typename T>
>
> T
>
> Get() const &
>
> {
>
> // return a copy of the stored value
>
> }
>
>
> template <typename T>
>
> T
>
> Get() &&
>
> {
>
> // move the stored value to the returned result
>
> }
>
>
> // And here we might want to have some aliases
>
> template <typename T>
>
> operator T() const &
>
> {
>
> return Get<T>();
>
> }
>
>
> template <typename T>
>
> operator T() &&
>
> {
>
> return std::move(*this).Get<T>();
>
> }
>
>
> template <typename T>
>
> T
>
> GetWithStuff() const &
>
> {
>
> return Get<T>() + Stuff<T>();
>
> }
>
>
> template <typename T>
>
> T
>
> GetWithStuff() &&
>
> {
>
> return std::move(*this).Get<T>() + Stuff<T>();
>
> }
>
> };
>
>
> The problem is that Get() method has some aliases (it might be another
> method with just different name or some generalized additional logic, or,
> for example, type casting operator). Did you also noticed copy-pasting
> which naturally seems must be avoided? What I basically might want from t=
he
> language, is the ability to perfectly forward =93*this=94 to some functio=
ns.
> Possible syntax (just the first idea):
>
>
> template <this ThisType, typename T>
>
> T
>
> GetWithStuff() ThisType && //roughly equivalent to "T&&" in arguments whe=
n
> using arguments forwarding
>
> {
>
> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>
> }
>
>
> I think =93this=94 keyword can be used in template parameters which is v=
ery
> natural. Also I feel that all rules applicable to type deduction of
> argument in =93T &&=94 form (in perfect forwarding pattern context), as w=
ell as
> all rules for argument types and templates there, should be the same for
> =93this=94 argument which is just written next to parenthesis. Thus such
> construction
>
>
> template <this ThisType, typename T>
>
> T
>
> GetWithStuff() const ThisType &
>
> {
>
> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>
> }
>
>
> will not have much sense (ThisType will be just =93Value=94) but still
> should work to make things consistent.
>
>
> May be having template parameter name in =93*this=94 specification part =
is
> redundant:
>
> template <this ThisType, typename T>
>
> T
>
> GetWithStuff() const & //presence of "this" in template parameters
> automatically applies it there
>
> {
>
> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>
> }
>
>
> Obviously =93this=94 can be used in template parameters for non-static c=
lass
> methods only.
>
>
> IMHO such feature would be a nice addition for making the language even
> more beautiful, and it should not be a problem to implement in compilers
> since =93this=94 argument already should be implicitly present (with type
> information) in most places, which are subject for the changes.
>
>
> Best regards,
>
> Artyom
>
> --
>
> ---
> 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/.
>
--=20
---=20
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 e=
mail 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-proposa=
ls/.
--001a11336ce2c28b2704e53fdaf2
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hello,<br><br>I've been thinking about the same proble=
m a few weeks ago. I was writing a blog post about 'rvalue references f=
or *this' (aka &&-member functions), in which I also complained=
a bit about how annoying it is to define an accessor properly (&, cons=
t &, &&, const &&, etc.) (<a href=3D"http://blog.m-ou.s=
e/2013/07/21/rvalue-references-for-this.html">http://blog.m-ou.se/2013/07/2=
1/rvalue-references-for-this.html</a>). The suggestion I gave had to 'f=
ix' this, is similar to yours:<br>
<br>class foo {<br>=A0 =A0 std::string name_;<br>public:<br>=A0 =A0 decltyp=
e(auto) name() T && { return std::forward<T>(*this).name_; }<=
br>}:<br><br>However, there's one big difference with your solution: He=
re, foo::name() is not a template. This syntax just and defines 8 different=
versions of foo::name (the &, const &, volatile &, const volat=
ile &, and all the && versions).<br>
<br>I'm not sure if it'd be better or not to make it a template (I =
haven't put very much thought into it yet), but I just wanted to mentio=
n this option.<br><br>Also, there needs to be some way to specify you only =
want to define all the & versions but not the && versions, or o=
nly the const versions. Something like:<br>
<br>void whatever() T & { ... }<br>void whatever() T const { ... }<br><=
br>This would make repeating the template paramaeter name after the argumen=
t list non-redundant in your template idea.<br><br>-Maurice-<br><br><pre>
<code class=3D""><span class=3D""><br></span></code></pre><br></div><div cl=
ass=3D"gmail_extra"><br><br><div class=3D"gmail_quote">2013/8/31 <span dir=
=3D"ltr"><<a href=3D"mailto:artyom.lebedev@gmail.com" target=3D"_blank">=
artyom.lebedev@gmail.com</a>></span><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr">
=09
=09
=09
=09
<p style=3D"margin-bottom:0in">Hi,</p>
<p style=3D"margin-bottom:0in">This in not a well-formed proposal but
just my thoughts about the subject feature. May be something similar is alr=
eady planned but I did not find it in C++14 features list.<br></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">So now, especially after introducing
=93N2439 - Extending move semantics to *this=94, (*this) can be
matched to differently qualified type:</p><p style=3D"margin-bottom:0in"><b=
r></p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">class A {</span></p><span style=3D"font-family:courier new,monospace"=
>
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method(); // 1. *this is "A&"</sp=
an></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method() const; // 2. *this is "const A&a=
mp;"</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method() volatile; // 3. *this is "volati=
le A&"</span></p><span style=3D"font-family:courier new,monospace"=
>
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method() const volatile; // 4.
*this is "const volatile A&"</span></p><span style=3D"font-fa=
mily:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method() &&; //5. matched
to "A &&" but in scope of method implementation *this is =
"A&" since it has name</span></p><span style=3D"font-family:c=
ourier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 void Method() const &&; //6.
This one and similar CV+rvalue_ref, may be not so meaningful in most
cases but still worth to mention. *this is "const A&",
probably always matches "A&&".</span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">};</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Currently there is no way to create a
method template, having type of =93*this=94 as template parameter. In
some cases you might want to have generic implementation for a method
and properly forward =93*this=94 to some other function. The number
of combinations for *this types reminds me the situation with
possible qualifiers for arguments in templates before perfect
forwarding pattern was introduced. Fortunately, now we have only one
problematic argument with dozen of choices (which were doubled after N2439)=
..</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Small real world example of the applicable
situation. Let's say I have a class which encapsulates some value.
The value has dynamic type, and may have underlying type which
requires heap allocation (e.g. string) so it is perfect for moving. I
have method Get<TargetType>() which returns the value. The
trick with the Get() method is that for =93rvalue *this=94 we can
move the stored value to the result returned to the caller (and this is
very cool language feature indeed).</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">class Value {</span></p><span style=3D"font-family:courier new,monosp=
ace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 T</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 Get() const &</span></p><span style=3D"font-fami=
ly:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 // return a copy of the stored value</sp=
an></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 T</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 Get() &&</span></p><span style=3D"font-famil=
y:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 // move the stored value to the returned
result</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 // And here we might want to have some
aliases</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 operator T() const &</span></p><span style=3D"fo=
nt-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 return Get<T>();</span></p><span s=
tyle=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 operator T() &&</span></p><span style=3D"fon=
t-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 return std::move(*this).Get<T>();<=
/span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 T</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 GetWithStuff() const &</span></p><span style=3D"=
font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 return Get<T>() + Stuff<T>()=
;</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 template <typename T></span></p><span style=3D=
"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 T</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 GetWithStuff() &&</span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 {</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0=A0=A0=A0=A0 return std::move(*this).Get<T>()
+ Stuff<T>();</span></p><span style=3D"font-family:courier new,monosp=
ace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 }</span></p><span style=3D"font-family:courier new,m=
onospace">
</span><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">};</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">The problem is that Get() method has
some aliases (it might be another method with just different name or
some generalized additional logic, or, for example, type casting
operator). Did you also noticed copy-pasting which naturally seems
must be avoided? What I basically might want from the language, is
the ability to perfectly forward =93*this=94 to some functions.
Possible syntax (just the first idea):</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() ThisType &&
//roughly equivalent to "T&&" in arguments when using
arguments forwarding</span></p><span style=3D"font-family:courier new,monos=
pace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">I think =93this=94 keyword can be used
in template parameters which is very natural. Also I feel that all
rules applicable to type deduction of argument in =93T &&=94
form (in perfect forwarding pattern context), as well as all rules
for argument types and templates there, should be the same for =93this=94
argument which is just written next to parenthesis. Thus such
construction</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() const ThisType &</span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">will not have much sense (ThisType will
be just =93Value=94) but still should work to make things consistent.</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">May be having template parameter name
in =93*this=94 specification part is redundant:</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() const & //presence
of "this" in template parameters automatically applies it there</=
span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">=A0=A0=A0 return
std::forward<ThisType>(*this).Get<T>() + Stuff<T>();</spa=
n></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Obviously =93this=94 can be used in
template parameters for non-static class methods only.</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">IMHO such feature would be a nice
addition for making the language even more beautiful, and it should
not be a problem to implement in compilers since =93this=94 argument
already should be implicitly present (with type information) in most
places, which are subject for the changes.</p><p style=3D"margin-bottom:0in=
"><br></p><p style=3D"margin-bottom:0in">Best regards,</p><p style=3D"margi=
n-bottom:0in">Artyom<span class=3D"HOEnZb"><font color=3D"#888888"><br></fo=
nt></span></p>
</div><span class=3D"HOEnZb"><font color=3D"#888888">
<p></p>
-- <br>
=A0<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</font></span></blockquote></div><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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 />
--001a11336ce2c28b2704e53fdaf2--
.
Author: Artyom Lebedev <artyom.lebedev@gmail.com>
Date: Sat, 31 Aug 2013 10:33:33 -0700 (PDT)
Raw View
------=_Part_99_5311462.1377970413676
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
>
> I'm not sure if it'd be better or not to make it a template (I haven't pu=
t=20
> very much thought into it yet), but I just wanted to mention this option.
>
I definitely sure that it must be a template. Basically we have a function=
=20
template which has "this" implicit argument type as a template parameter,=
=20
i.e. depending on the provided "this" argument type different function code=
=20
is instantiated - this is true for this case and it is how templates work.=
=20
Also examples below in this message will show, how it is close to usual=20
templatized argument.
Also, there needs to be some way to specify you only want to define all the=
=20
> & versions but not the && versions, or only the const versions. Something=
=20
> like:
>
> void whatever() T & { ... }
> void whatever() T const { ... }
>
> This would make repeating the template paramaeter name after the argument=
=20
> list non-redundant in your template idea.
>
Think about it as it would be a regular function, for example, with such=20
definition:
template <class ThisType>
void
Method(ThisType &&thisRef)
{
// thisRef is *this
}
which could have such equivalent:
template <this ThisType>
void
Method() &&
{
}
As I have written before, all rules for types matching and deduction for=20
arguments should work for this case. In such case, this example would match=
=20
both "const ThisType &" (ThisType deduced to "const ClassType &" and=20
"ThisType &&" (ThisType deduced to "ClassType") , and "ThisType &"=20
(ThisType deduced to "ClassType &") - in the way it is described in=20
std::forward example: http://en.cppreference.com/w/cpp/utility/forward. So,=
=20
in other example:
template <this ThisType>
void
Method() & //think it is Method(ThisType &)
{
}
the method will match only "[const and/or volatile] ThisType &" and=20
"ThisType &" (deducing to the "const and/or volatile ClassType" and=20
"ClassType"), not "ThisType &&" (which should produce the same error, e.g.=
=20
in GCC - "invalid initialization of non-const reference of type =91... &=92=
=20
from an rvalue of type ..."), just like it would be if it was written as=20
argument:
template <class ThisType>
void
Method(ThisType &thisRef)
{
// thisRef is *this
}
So what I want to say, is that CV-qualifiers and lvalue/rvalue reference=20
after parenthesis is just a syntactic sugar for the case if "this" argument=
=20
was explicit and was written inside parenthesis and with the name. And=20
still seems that the name is not needed there because we always know what=
=20
and where it is. Correct me if I'm wrong.
Maurice Bos:
>
> Hello,
>
> I've been thinking about the same problem a few weeks ago. I was writing =
a=20
> blog post about 'rvalue references for *this' (aka &&-member functions), =
in=20
> which I also complained a bit about how annoying it is to define an=20
> accessor properly (&, const &, &&, const &&, etc.) (
> http://blog.m-ou.se/2013/07/21/rvalue-references-for-this.html). The=20
> suggestion I gave had to 'fix' this, is similar to yours:
>
> class foo {
> std::string name_;
> public:
> decltype(auto) name() T && { return std::forward<T>(*this).name_; }
> }:
>
> However, there's one big difference with your solution: Here, foo::name()=
=20
> is not a template. This syntax just and defines 8 different versions of=
=20
> foo::name (the &, const &, volatile &, const volatile &, and all the &&=
=20
> versions).
>
> I'm not sure if it'd be better or not to make it a template (I haven't pu=
t=20
> very much thought into it yet), but I just wanted to mention this option.
>
> Also, there needs to be some way to specify you only want to define all=
=20
> the & versions but not the && versions, or only the const versions.=20
> Something like:
>
> void whatever() T & { ... }
> void whatever() T const { ... }
>
> This would make repeating the template paramaeter name after the argument=
=20
> list non-redundant in your template idea.
>
> -Maurice-
>
>
>
>
>
> 2013/8/31 <artyom....@gmail.com <javascript:>>
>
>> Hi,
>>
>> This in not a well-formed proposal but just my thoughts about the subjec=
t=20
>> feature. May be something similar is already planned but I did not find =
it=20
>> in C++14 features list.
>>
>>
>> So now, especially after introducing =93N2439 - Extending move semantic=
s=20
>> to *this=94, (*this) can be matched to differently qualified type:
>>
>>
>> class A {
>>
>> void Method(); // 1. *this is "A&"
>>
>> void Method() const; // 2. *this is "const A&"
>>
>> void Method() volatile; // 3. *this is "volatile A&"
>>
>> void Method() const volatile; // 4. *this is "const volatile A&"
>>
>> void Method() &&; //5. matched to "A &&" but in scope of method=20
>> implementation *this is "A&" since it has name
>>
>> void Method() const &&; //6. This one and similar CV+rvalue_ref, may=
=20
>> be not so meaningful in most cases but still worth to mention. *this is=
=20
>> "const A&", probably always matches "A&&".
>>
>> };
>>
>>
>> Currently there is no way to create a method template, having type of=
=20
>> =93*this=94 as template parameter. In some cases you might want to have =
generic=20
>> implementation for a method and properly forward =93*this=94 to some oth=
er=20
>> function. The number of combinations for *this types reminds me the=20
>> situation with possible qualifiers for arguments in templates before=20
>> perfect forwarding pattern was introduced. Fortunately, now we have only=
=20
>> one problematic argument with dozen of choices (which were doubled after=
=20
>> N2439).
>>
>>
>> Small real world example of the applicable situation. Let's say I have=
=20
>> a class which encapsulates some value. The value has dynamic type, and m=
ay=20
>> have underlying type which requires heap allocation (e.g. string) so it =
is=20
>> perfect for moving. I have method Get<TargetType>() which returns the=20
>> value. The trick with the Get() method is that for =93rvalue *this=94 we=
can=20
>> move the stored value to the result returned to the caller (and this is=
=20
>> very cool language feature indeed).
>>
>>
>> class Value {
>>
>>
>> template <typename T>
>>
>> T
>>
>> Get() const &
>>
>> {
>>
>> // return a copy of the stored value
>>
>> }
>>
>>
>> template <typename T>
>>
>> T
>>
>> Get() &&
>>
>> {
>>
>> // move the stored value to the returned result
>>
>> }
>>
>>
>> // And here we might want to have some aliases
>>
>> template <typename T>
>>
>> operator T() const &
>>
>> {
>>
>> return Get<T>();
>>
>> }
>>
>>
>> template <typename T>
>>
>> operator T() &&
>>
>> {
>>
>> return std::move(*this).Get<T>();
>>
>> }
>>
>>
>> template <typename T>
>>
>> T
>>
>> GetWithStuff() const &
>>
>> {
>>
>> return Get<T>() + Stuff<T>();
>>
>> }
>>
>>
>> template <typename T>
>>
>> T
>>
>> GetWithStuff() &&
>>
>> {
>>
>> return std::move(*this).Get<T>() + Stuff<T>();
>>
>> }
>> =20
>> };
>>
>>
>> The problem is that Get() method has some aliases (it might be another=
=20
>> method with just different name or some generalized additional logic, or=
,=20
>> for example, type casting operator). Did you also noticed copy-pasting=
=20
>> which naturally seems must be avoided? What I basically might want from =
the=20
>> language, is the ability to perfectly forward =93*this=94 to some functi=
ons.=20
>> Possible syntax (just the first idea):
>>
>>
>> template <this ThisType, typename T>
>>
>> T
>>
>> GetWithStuff() ThisType && //roughly equivalent to "T&&" in arguments=20
>> when using arguments forwarding
>>
>> {
>>
>> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>>
>> }
>>
>>
>> I think =93this=94 keyword can be used in template parameters which is =
very=20
>> natural. Also I feel that all rules applicable to type deduction of=20
>> argument in =93T &&=94 form (in perfect forwarding pattern context), as =
well as=20
>> all rules for argument types and templates there, should be the same for=
=20
>> =93this=94 argument which is just written next to parenthesis. Thus such=
=20
>> construction
>>
>>
>> template <this ThisType, typename T>
>>
>> T
>>
>> GetWithStuff() const ThisType &
>>
>> {
>>
>> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>>
>> }
>>
>>
>> will not have much sense (ThisType will be just =93Value=94) but still=
=20
>> should work to make things consistent.
>>
>>
>> May be having template parameter name in =93*this=94 specification part=
is=20
>> redundant:
>>
>> template <this ThisType, typename T>
>>
>> T
>>
>> GetWithStuff() const & //presence of "this" in template parameters=20
>> automatically applies it there
>>
>> {
>>
>> return std::forward<ThisType>(*this).Get<T>() + Stuff<T>();
>>
>> }
>>
>>
>> Obviously =93this=94 can be used in template parameters for non-static=
=20
>> class methods only.
>>
>>
>> IMHO such feature would be a nice addition for making the language even=
=20
>> more beautiful, and it should not be a problem to implement in compilers=
=20
>> since =93this=94 argument already should be implicitly present (with typ=
e=20
>> information) in most places, which are subject for the changes.
>>
>>
>> Best regards,
>>
>> Artyom
>> =20
>> --=20
>> =20
>> ---=20
>> You received this message because you are subscribed to the Google Group=
s=20
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n=20
>> email to std-proposal...@isocpp.org <javascript:>.
>> To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>> Visit this group at=20
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>
>
--=20
---=20
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 e=
mail 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-proposa=
ls/.
------=_Part_99_5311462.1377970413676
Content-Type: text/html; charset=windows-1252
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">=
I'm not sure if it'd be better or not to make it a template (I haven't=20
put very much thought into it yet), but I just wanted to mention this=20
option.<br></blockquote>I definitely sure that it must be a template. Basic=
ally we have a function template which has "this" implicit argument type as=
a template parameter, i.e. depending on the provided "this" argument type =
different function code is instantiated - this is true for this case and it=
is how templates work. Also examples below in this message will show, how =
it is close to usual templatized argument.<br><br><blockquote style=3D"marg=
in: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-l=
eft: 1ex;" class=3D"gmail_quote">Also, there needs to be some way to specif=
y you only want to define all=20
the & versions but not the && versions, or only the const=20
versions. Something like:<br>
<br>void whatever() T & { ... }<br>void whatever() T const { ... }<br><=
br>This would make repeating the template paramaeter name after the argumen=
t list non-redundant in your template idea.<br></blockquote><br>Think about=
it as it would be a regular function, for example, with such definition:<b=
r><span style=3D"font-family: courier new,monospace;">template <class Th=
isType><br>void<br>Method(ThisType &&thisRef)<br>{<br>// thisRef=
is *this<br>}</span><br>which could have such equivalent:<br><span style=
=3D"font-family: courier new,monospace;">template <this ThisType><br>=
void<br>Method() &&<br>{<br>}</span><br>As I have written before, a=
ll rules for types matching and deduction for arguments should work for thi=
s case. In such case, this example would match both "const ThisType &" =
(ThisType deduced to "const ClassType &" and "ThisType &&" (Thi=
sType deduced to "ClassType") , and "ThisType &" (ThisType deduced to "=
ClassType &") - in the way it is described in std::forward example: htt=
p://en.cppreference.com/w/cpp/utility/forward. So, in other example:<br><sp=
an style=3D"font-family: courier new,monospace;">template <this ThisType=
><br>void<br>Method() & //think it is Method(ThisType &)<br>{<br=
>}</span><br>the method will match only "[const and/or volatile] ThisType &=
amp;" and "ThisType &" (deducing to the "const and/or volatile ClassTyp=
e" and "ClassType"), not "ThisType &&" (which should produce the sa=
me error, e.g. in GCC - "invalid initialization of non-const reference of t=
ype =91... &=92 from an rvalue of type ..."), just like it would be if =
it was written as argument:<br><span style=3D"font-family: courier new,mono=
space;">template <class ThisType><br>void<br>Method(ThisType &thi=
sRef)<br>{<br>// thisRef is *this<br>}</span><br><br>So what I want to say,=
is that CV-qualifiers and lvalue/rvalue reference after parenthesis is jus=
t a syntactic sugar for the case if "this" argument was explicit and was wr=
itten inside parenthesis and with the name. And still seems that the name i=
s not needed there because we always know what and where it is. Correct me =
if I'm wrong.<br><br>Maurice Bos:<blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;"><div dir=3D"ltr">Hello,<br><br>I've been thinking about the same problem=
a few weeks ago. I was writing a blog post about 'rvalue references for *t=
his' (aka &&-member functions), in which I also complained a bit ab=
out how annoying it is to define an accessor properly (&, const &, =
&&, const &&, etc.) (<a href=3D"http://blog.m-ou.se/2013/07=
/21/rvalue-references-for-this.html" target=3D"_blank">http://blog.m-ou.se/=
2013/07/<wbr>21/rvalue-references-for-this.<wbr>html</a>). The suggestion I=
gave had to 'fix' this, is similar to yours:<br>
<br>class foo {<br> std::string name_;<br>public:<br> &n=
bsp; decltype(auto) name() T && { return std::forward<T>(*thi=
s).name_; }<br>}:<br><br>However, there's one big difference with your solu=
tion: Here, foo::name() is not a template. This syntax just and defines 8 d=
ifferent versions of foo::name (the &, const &, volatile &, con=
st volatile &, and all the && versions).<br>
<br>I'm not sure if it'd be better or not to make it a template (I haven't =
put very much thought into it yet), but I just wanted to mention this optio=
n.<br><br>Also, there needs to be some way to specify you only want to defi=
ne all the & versions but not the && versions, or only the cons=
t versions. Something like:<br>
<br>void whatever() T & { ... }<br>void whatever() T const { ... }<br><=
br>This would make repeating the template paramaeter name after the argumen=
t list non-redundant in your template idea.<br><br>-Maurice-<br><br><pre><c=
ode><span><br></span></code></pre><br></div><div><br><br><div class=3D"gmai=
l_quote">2013/8/31 <span dir=3D"ltr"><<a href=3D"javascript:" target=3D=
"_blank" gdf-obfuscated-mailto=3D"M_HsX-4ZM5cJ">artyom....@gmail.com</a>>=
;</span><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr">
=09
=09
=09
=09
<p style=3D"margin-bottom:0in">Hi,</p>
<p style=3D"margin-bottom:0in">This in not a well-formed proposal but
just my thoughts about the subject feature. May be something similar is alr=
eady planned but I did not find it in C++14 features list.<br></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">So now, especially after introducing
=93N2439 - Extending move semantics to *this=94, (*this) can be
matched to differently qualified type:</p><p style=3D"margin-bottom:0in"><b=
r></p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">class A {</span></p><span style=3D"font-family:courier new,monospace"=
>
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method(); // 1. *this is "A&"</spa=
n></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method() const; // 2. *this is "const=
A&"</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method() volatile; // 3. *this is "vo=
latile A&"</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method() const volatile; // 4.
*this is "const volatile A&"</span></p><span style=3D"font-family:couri=
er new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method() &&; //5. matched
to "A &&" but in scope of method implementation *this is "A&" s=
ince it has name</span></p><span style=3D"font-family:courier new,monospace=
">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> void Method() const &&; //6.
This one and similar CV+rvalue_ref, may be not so meaningful in most
cases but still worth to mention. *this is "const A&",
probably always matches "A&&".</span></p><span style=3D"font-family=
:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">};</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Currently there is no way to create a
method template, having type of =93*this=94 as template parameter. In
some cases you might want to have generic implementation for a method
and properly forward =93*this=94 to some other function. The number
of combinations for *this types reminds me the situation with
possible qualifiers for arguments in templates before perfect
forwarding pattern was introduced. Fortunately, now we have only one
problematic argument with dozen of choices (which were doubled after N2439)=
..</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Small real world example of the applicable
situation. Let's say I have a class which encapsulates some value.
The value has dynamic type, and may have underlying type which
requires heap allocation (e.g. string) so it is perfect for moving. I
have method Get<TargetType>() which returns the value. The
trick with the Get() method is that for =93rvalue *this=94 we can
move the stored value to the result returned to the caller (and this is
very cool language feature indeed).</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">class Value {</span></p><span style=3D"font-family:courier new,monosp=
ace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> T</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> Get() const &</span></p><span style=3D"=
font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> // return a copy of=
the stored value</span></p><span style=3D"font-family:courier new,monospac=
e">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> T</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> Get() &&</span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> // move the stored =
value to the returned
result</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> // And here we might want to have some
aliases</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> operator T() const &</span></p><span st=
yle=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return Get<T>=
();</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> operator T() &&</span></p><span sty=
le=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return std::move(*t=
his).Get<T>();</span></p><span style=3D"font-family:courier new,monos=
pace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> T</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> GetWithStuff() const &</span></p><span =
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return Get<T>=
() + Stuff<T>();</span></p><span style=3D"font-family:courier new,mon=
ospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"><br></span>
</p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> template <typename T></span></p><span=
style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> T</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> GetWithStuff() &&</span></p><span s=
tyle=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> {</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return std::move(*t=
his).Get<T>()
+ Stuff<T>();</span></p><span style=3D"font-family:courier new,monosp=
ace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> }</span></p><span style=3D"font-family:cour=
ier new,monospace">
</span><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">};</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">The problem is that Get() method has
some aliases (it might be another method with just different name or
some generalized additional logic, or, for example, type casting
operator). Did you also noticed copy-pasting which naturally seems
must be avoided? What I basically might want from the language, is
the ability to perfectly forward =93*this=94 to some functions.
Possible syntax (just the first idea):</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() ThisType &&
//roughly equivalent to "T&&" in arguments when using
arguments forwarding</span></p><span style=3D"font-family:courier new,monos=
pace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return
std::forward<ThisType>(*this).<wbr>Get<T>() + Stuff<T>();=
</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">I think =93this=94 keyword can be used
in template parameters which is very natural. Also I feel that all
rules applicable to type deduction of argument in =93T &&=94
form (in perfect forwarding pattern context), as well as all rules
for argument types and templates there, should be the same for =93this=94
argument which is just written next to parenthesis. Thus such
construction</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() const ThisType &</span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return
std::forward<ThisType>(*this).<wbr>Get<T>() + Stuff<T>();=
</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">will not have much sense (ThisType will
be just =93Value=94) but still should work to make things consistent.</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">May be having template parameter name
in =93*this=94 specification part is redundant:</p>
<p style=3D"margin-bottom:0in"><span style=3D"font-family:courier new,monos=
pace">template <this ThisType, typename T></span></p><span style=3D"f=
ont-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">T</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">GetWithStuff() const & //presence
of "this" in template parameters automatically applies it there</span></p><=
span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">{</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace"> return
std::forward<ThisType>(*this).<wbr>Get<T>() + Stuff<T>();=
</span></p><span style=3D"font-family:courier new,monospace">
</span><p style=3D"margin-bottom:0in"><span style=3D"font-family:courier ne=
w,monospace">}</span></p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">Obviously =93this=94 can be used in
template parameters for non-static class methods only.</p>
<p style=3D"margin-bottom:0in"><br>
</p>
<p style=3D"margin-bottom:0in">IMHO such feature would be a nice
addition for making the language even more beautiful, and it should
not be a problem to implement in compilers since =93this=94 argument
already should be implicitly present (with type information) in most
places, which are subject for the changes.</p><p style=3D"margin-bottom:0in=
"><br></p><p style=3D"margin-bottom:0in">Best regards,</p><p style=3D"margi=
n-bottom:0in">Artyom<span><font color=3D"#888888"><br></font></span></p>
</div><span><font color=3D"#888888">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
M_HsX-4ZM5cJ">std-proposal...@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"javascript:" target=3D"_bla=
nk" gdf-obfuscated-mailto=3D"M_HsX-4ZM5cJ">std-pr...@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/<wbr>isocpp.or=
g/group/std-<wbr>proposals/</a>.<br>
</font></span></blockquote></div><br></div>
</blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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_99_5311462.1377970413676--
.
Author: Maurice Bos <m-ou.se@m-ou.se>
Date: Sat, 31 Aug 2013 20:01:06 +0200
Raw View
--089e013d14b2b49f9404e542203f
Content-Type: text/plain; charset=ISO-8859-1
2013/8/31 Artyom Lebedev <artyom.lebedev@gmail.com>
> I'm not sure if it'd be better or not to make it a template (I haven't put
>> very much thought into it yet), but I just wanted to mention this option.
>>
> I definitely sure that it must be a template. Basically we have a function
> template which has "this" implicit argument type as a template parameter,
> i.e. depending on the provided "this" argument type different function code
> is instantiated - this is true for this case and it is how templates work.
> Also examples below in this message will show, how it is close to usual
> templatized argument.
>
Yes, I agree a template is better.
>
> Also, there needs to be some way to specify you only want to define all
>> the & versions but not the && versions, or only the const versions.
>> Something like:
>>
>> void whatever() T & { ... }
>> void whatever() T const { ... }
>>
>> This would make repeating the template paramaeter name after the argument
>> list non-redundant in your template idea.
>>
>
> (snip)
>
> So what I want to say, is that CV-qualifiers and lvalue/rvalue reference
> after parenthesis is just a syntactic sugar for the case if "this" argument
> was explicit and was written inside parenthesis and with the name. And
> still seems that the name is not needed there because we always know what
> and where it is. Correct me if I'm wrong.
>
Ah yes, I see.
--
---
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/.
--089e013d14b2b49f9404e542203f
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><div class=3D"gmail_quote">=
2013/8/31 Artyom Lebedev <span dir=3D"ltr"><<a href=3D"mailto:artyom.leb=
edev@gmail.com" target=3D"_blank">artyom.lebedev@gmail.com</a>></span><b=
r><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex">
<div dir=3D"ltr"><div class=3D"im"><blockquote style=3D"margin:0px 0px 0px =
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class=3D"gma=
il_quote">I'm not sure if it'd be better or not to make it a templa=
te (I haven't=20
put very much thought into it yet), but I just wanted to mention this=20
option.<br></blockquote></div>I definitely sure that it must be a template.=
Basically we have a function template which has "this" implicit =
argument type as a template parameter, i.e. depending on the provided "=
;this" argument type different function code is instantiated - this is=
true for this case and it is how templates work. Also examples below in th=
is message will show, how it is close to usual templatized argument.</div>
</blockquote><div><br>Yes, I agree a template is better.<br>=A0</div><block=
quote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"im"><br><blockquote=
style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);p=
adding-left:1ex" class=3D"gmail_quote">
Also, there needs to be some way to specify you only want to define all=20
the & versions but not the && versions, or only the const=20
versions. Something like:<br>
<br>void whatever() T & { ... }<br>void whatever() T const { ... }<br><=
br>This would make repeating the template paramaeter name after the argumen=
t list non-redundant in your template idea.<br></blockquote><br></div>
(snip)<br><br>So what I want to say, is that CV-qualifiers and lvalue/rvalu=
e reference after parenthesis is just a syntactic sugar for the case if &qu=
ot;this" argument was explicit and was written inside parenthesis and =
with the name. And still seems that the name is not needed there because we=
always know what and where it is. Correct me if I'm wrong.<br>
</div></blockquote><div><br>Ah yes, I see. <br></div></div></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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 />
--089e013d14b2b49f9404e542203f--
.
Author: David Krauss <potswa@gmail.com>
Date: Sat, 31 Aug 2013 19:26:42 -0700 (PDT)
Raw View
------=_Part_1511_23485993.1378002403000
Content-Type: text/plain; charset=ISO-8859-1
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_1511_23485993.1378002403000
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I must admit I didn't read your entire post.<br><br>You ca=
n't get the actual type of the argument which initialized *this; as noted o=
nly templates can represent simultaneous types and otherwise you have all t=
he combinations of cv-qualification and value category.<br><br>What you can=
do is forgo a member function and use ADL and a non-member function templa=
te with perfect forwarding regulated by SFINAE. This gets you not only cv-q=
ualification and value category but also the static type from the call site=
..<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250=
, 250); border-color: rgb(187, 187, 187); border-style: solid; border-width=
: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"su=
bprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">str=
uct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> s </sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br><br> </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">template</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">typename</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">self</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">></span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br> </span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">friend</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">typename</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">e=
nable_if</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&l=
t;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">is_base_of</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> s</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">typename</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">decay</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
<</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">self</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">>::</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">type </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">>::</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">value</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br> std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">decltype</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">declval</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify"><</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">se=
lf</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">>().</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">x </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">>::</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">type<br> get_x</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">self</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&&</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> o </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nb=
sp; </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">ret=
urn</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">forward</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">self</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">>(</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> o </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">).</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span></div></code></div><br>If I were yo=
u, though, I'd just elaborate the accessor functions as before and delegate=
from the rvalue overload to the lvalue overload with an explicit <span sty=
le=3D"font-family: courier new,monospace;">move</span>. As you mentioned, c=
onst rvalue isn't actually used for anything, so the <span style=3D"font-fa=
mily: courier new,monospace;">const</span> overload need not be ref-qualifi=
ed. So the new change doesn't effectively double the complexity, but in usu=
al practice only one new case is added, which essentially just forwards 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>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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_1511_23485993.1378002403000--
.
Author: Artyom Lebedev <artyom.lebedev@gmail.com>
Date: Sun, 1 Sep 2013 00:23:44 -0700 (PDT)
Raw View
------=_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<std::string> o=
r std::vector<std::string>. 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 &" creates a new list with copies of necessary componen=
t strings. The version for "*this" =3D "ClassType &&"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> std::vector<std::string> compo=
nents;<br><br> Path(std::vector<std::string> &&=
amp;components):<br> components(c=
omponents)<br> {}<br>public:<br> //vers=
ion for lvalue<br> Path<br> Slice(size_=
t start, size_t count) const &<br> {<br> &=
nbsp; //create new components list<br> &=
nbsp; std::vector<std::string> slice;<br>&nbs=
p; //populate it with necessary compone=
nts<br> ...<br> =
return Path(std::move(slice));<br> &nbs=
p; }<br><br> //version for rvalue<br> P=
ath<br> Slice(size_t start, size_t count) &&<br>&=
nbsp; {<br> //just tr=
im unnecessary components from own list<br> &n=
bsp; if (start !=3D 0) {<br>  =
; components.erase(components.begin(), components.b=
egin() + start);<br> }<br> &=
nbsp; components.resize(count);<br> &nbs=
p; //return this object as the result<br>&nbs=
p; return std::move(*this);<br> &n=
bsp; }<br><br> //This is full of copy-paste current=
approach<br> Path<br> BaseName() const=
&<br> {<br>  =
; if (components.empty()) {<br> &n=
bsp; return Path();<br> &nbs=
p; }<br> return Slice(compo=
nents.size() - 1, components.size());<br> }<br><br> =
Path<br> BaseName() &&<br> &nbs=
p; {<br> if (components.emp=
ty()) {<br> &nbs=
p; return std::move(*this);<br> }=
<br> return std::move(*this).Slic=
e(components.size() - 1, components.size());<br> }<br><br=
> Path<br> DirName() const &<br>&nb=
sp; {<br> if (compone=
nts.empty()) {<br> &nb=
sp; return Path();<br> }<br=
> return Slice(0, components.size=
() - 1);<br> }<br><br> Path<br> &n=
bsp; DirName() &&<br> {<br> &nbs=
p; if (components.empty()) {<br> &=
nbsp; return std::move(*this);<br=
> }<br> &n=
bsp; return std::move(*this).Slice(0, components.size() - 1);<b=
r> }<br><br> //And this the proposed on=
e<br> template <this PathType><br>  =
; PathType<br> BaseName() &&<br>  =
; {<br> if (components.empty()) {=
<br> retu=
rn std::forward<PathType>(*this);<br> &n=
bsp; }<br> return std::forw=
ard<PathType>(*this).Slice(components.size() - 1, components.size());=
<br> }<br><br> template <this PathTy=
pe><br> Path<br> DirName() &&=
;<br> {<br> if =
(components.empty()) {<br> &=
nbsp; return std::forward<PathType>(*this);<br> &nbs=
p; }<br> &=
nbsp; return std::forward<PathType>(*this).Slice(0, components.size()=
- 1);<br> }<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> Cons=
t qualifier is a bit special, in the meaning that rvalue is matched to "con=
st T &". 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> </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> </span><span style=3D"color:#008">=
template</span><span style=3D"color:#660"><</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">></span><span style=3D"color:#00=
0"><br> </span><span style=3D"color:#008">friend</span><span s=
tyle=3D"color:#000"><br> </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"><</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"><</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"><</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">>::</span><span style=3D"color:#000">type </span><span style=3D"c=
olor:#660">>::</span><span style=3D"color:#000">value</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"><br> =
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"><</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">>().</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">>::</span><span style=3D"color:=
#000">type<br> 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">&&</spa=
n><span style=3D"color:#000"> o </span><span style=3D"color:#660">)</span><=
span style=3D"color:#000"><br> </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"><</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">>(</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 />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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--
.
Author: Maurice Bos <m-ou.se@m-ou.se>
Date: Sun, 1 Sep 2013 11:51:25 +0200
Raw View
--089e0112c51c4c912b04e54f67d3
Content-Type: text/plain; charset=ISO-8859-1
Two other examples to consider are implementations of optional<T> and
variant<T...>. *optional, optional.get(), variant.get_as<T>() etc. should
return the same kind of reference with the same cv-qualifiers as the
optional/variant itself. (So give_me_an_optional_string().get() should give
std::string&&.)
2013/9/1 Artyom Lebedev <artyom.lebedev@gmail.com>
> 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/.
>
--
---
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/.
--089e0112c51c4c912b04e54f67d3
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Two other examples to consider are implementations of opti=
onal<T> and variant<T...>. *optional, optional.get(), variant.g=
et_as<T>() etc. should return the same kind of reference with the sam=
e cv-qualifiers as the optional/variant itself. (So give_me_an_optional_str=
ing().get() should give std::string&&.)<br>
</div><div class=3D"gmail_extra"><br><br><div class=3D"gmail_quote">2013/9/=
1 Artyom Lebedev <span dir=3D"ltr"><<a href=3D"mailto:artyom.lebedev@gma=
il.com" target=3D"_blank">artyom.lebedev@gmail.com</a>></span><br><block=
quote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc=
solid;padding-left:1ex">
<div dir=3D"ltr"><div class=3D"im"><blockquote style=3D"margin:0px 0px 0px =
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class=3D"gma=
il_quote">Standard disclaimer: accessor functions are evil. C++ has a perfe=
ctly=20
good model for accessing members; do not roll your own unless you=20
legitimately have a custom object model.<br></blockquote></div><div>Probabl=
y you a bit misunderstood the idea. It by no means related to accessor func=
tions. 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 me=
thod. So I will provide another example for better understanding of use cas=
es.<br>
<br>Let's say we have a class which represents some path in a filesyste=
m (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 "*thi=
s" =3D "const ClassType &" creates a new list with copie=
s of necessary component strings. The version for "*this" =3D &qu=
ot;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 sho=
uld return path part before the last component and last component only. Obv=
iously, 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:<br>
<br><span style=3D"font-family:courier new,monospace">class Path {<br>priva=
te:<br>=A0=A0=A0 std::vector<std::string> components;<br><br>=A0=A0=
=A0 Path(std::vector<std::string> &&components):<br>=A0=A0=A0=
=A0=A0=A0=A0 components(components)<br>
=A0=A0=A0 {}<br>public:<br>=A0=A0=A0 //version for lvalue<br>=A0=A0=A0 Path=
<br>=A0=A0=A0 Slice(size_t start, size_t count) const &<br>=A0=A0=A0 {<=
br>=A0=A0=A0=A0=A0=A0=A0 //create new components list<br>=A0=A0=A0=A0=A0=A0=
=A0 std::vector<std::string> slice;<br>=A0=A0=A0=A0=A0=A0=A0 //popula=
te it with necessary components<br>
=A0=A0=A0=A0=A0=A0=A0 ...<br>=A0=A0=A0=A0=A0=A0=A0 return Path(std::move(sl=
ice));<br>=A0=A0=A0 }<br><br>=A0=A0=A0 //version for rvalue<br>=A0=A0=A0 Pa=
th<br>=A0=A0=A0 Slice(size_t start, size_t count) &&<br>=A0=A0=A0 {=
<br>=A0=A0=A0=A0=A0=A0=A0 //just trim unnecessary components from own list<=
br>
=A0=A0=A0=A0=A0=A0=A0 if (start !=3D 0) {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0 components.erase(components.begin(), components.begin() + start);<br>=
=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=A0=A0=A0=A0=A0 components.resize(count);<=
br>=A0=A0=A0=A0=A0=A0=A0 //return this object as the result<br>=A0=A0=A0=A0=
=A0=A0=A0 return std::move(*this);<br>
=A0=A0=A0 }<br><br>=A0=A0=A0 //This is full of copy-paste current approach<=
br>=A0=A0=A0 Path<br>=A0=A0=A0 BaseName() const &<br>=A0=A0=A0 {<br>=A0=
=A0=A0=A0=A0=A0=A0 if (components.empty()) {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0 return Path();<br>=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=A0=A0=A0=A0=A0 r=
eturn Slice(components.size() - 1, components.size());<br>
=A0=A0=A0 }<br><br>=A0=A0=A0 Path<br>=A0=A0=A0 BaseName() &&<br>=A0=
=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0 if (components.empty()) {<br>=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0 return std::move(*this);<br>=A0=A0=A0=A0=A0=A0=A0 }<b=
r>=A0=A0=A0=A0=A0=A0=A0 return std::move(*this).Slice(components.size() - 1=
, components.size());<br>
=A0=A0=A0 }<br><br>=A0=A0=A0 Path<br>=A0=A0=A0 DirName() const &<br>=A0=
=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0 if (components.empty()) {<br>=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0 return Path();<br>=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=
=A0=A0=A0=A0=A0 return Slice(0, components.size() - 1);<br>=A0=A0=A0 }<br><=
br>=A0=A0=A0 Path<br>=A0=A0=A0 DirName() &&<br>
=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0 if (components.empty()) {<br>=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 return std::move(*this);<br>=A0=A0=A0=A0=A0=A0=A0 =
}<br>=A0=A0=A0=A0=A0=A0=A0 return std::move(*this).Slice(0, components.size=
() - 1);<br>=A0=A0=A0 }<br><br>=A0=A0=A0 //And this the proposed one<br>=A0=
=A0=A0 template <this PathType><br>
=A0=A0=A0 PathType<br>=A0=A0=A0 BaseName() &&<br>=A0=A0=A0 {<br>=A0=
=A0=A0=A0=A0=A0=A0 if (components.empty()) {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0 return std::forward<PathType>(*this);<br>=A0=A0=A0=A0=A0=A0=A0=
}<br>=A0=A0=A0=A0=A0=A0=A0 return std::forward<PathType>(*this).Slic=
e(components.size() - 1, components.size());<br>
=A0=A0=A0 }<br><br>=A0=A0=A0 template <this PathType><br>=A0=A0=A0 Pa=
th<br>=A0=A0=A0 DirName() &&<br>=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=
=A0 if (components.empty()) {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return s=
td::forward<PathType>(*this);<br>=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=A0=
=A0=A0=A0=A0 return std::forward<PathType>(*this).Slice(0, components=
..size() - 1);<br>
=A0=A0=A0 }<br>};</span><br><br>I hope this example is much more clear. In =
general, the idea is that now we have full set of qualifiers for "*thi=
s", 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.<div class=3D"im">
<br><br><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid=
rgb(204,204,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></div>Yes, I fully understand this, and as I described in previo=
us 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.<div class=3D"im">
<br><br><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid=
rgb(204,204,204);padding-left:1ex" class=3D"gmail_quote">As you mentioned,=
const rvalue isn't actually used for anything, so the <span style=3D"f=
ont-family:courier new,monospace">const</span> overload need not be ref-qua=
lified. </blockquote>
</div><div>=A0Const qualifier is a bit special, in the meaning that rvalue =
is matched to "const T &". But do not forget about "vola=
tile", there also might be use cases for it.<br></div><br></div>David =
Krauss:<div>
<div class=3D"h5"><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">=
I must admit I didn't read your entire post.<br><br>You can't get t=
he actual type of the argument which initialized *this; as noted only templ=
ates can represent simultaneous types and otherwise you have all the combin=
ations of cv-qualification and value category.<br>
<br>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 y=
ou not only cv-qualification and value category but also the static type fr=
om the call site.<br>
<br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,18=
7,187);border-style:solid;border-width:1px;word-wrap:break-word"><code><div=
><span style=3D"color:#008">struct</span><span style> s </span><span style=
=3D"color:#660">{</span><span style><br>
=A0 =A0 </span><span style=3D"color:#008">int</span><span style> x</span><s=
pan style=3D"color:#660">;</span><span style><br><br>=A0 =A0 </span><span s=
tyle=3D"color:#008">template</span><span style=3D"color:#660"><</span><s=
pan style> </span><span style=3D"color:#008">typename</span><span style> </=
span><span style=3D"color:#008">self</span><span style> </span><span style=
=3D"color:#660">></span><span style><br>
=A0 =A0 </span><span style=3D"color:#008">friend</span><span style><br>=A0 =
=A0 </span><span style=3D"color:#008">typename</span><span style> std</span=
><span style=3D"color:#660">::</span><span style>enable_if</span><span styl=
e=3D"color:#660"><</span><span style> std</span><span style=3D"color:#66=
0">::</span><span style>is_base_of</span><span style=3D"color:#660"><</s=
pan><span style> s</span><span style=3D"color:#660">,</span><span style> </=
span><span style=3D"color:#008">typename</span><span style> std</span><span=
style=3D"color:#660">::</span><span style>decay</span><span style=3D"color=
:#660"><</span><span style> </span><span style=3D"color:#008">self</span=
><span style> </span><span style=3D"color:#660">>::</span><span style>ty=
pe </span><span style=3D"color:#660">>::</span><span style>value</span><=
span style=3D"color:#660">,</span><span style><br>
=A0 =A0 =A0 =A0 std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#008">decltype</span><span style=3D"color:#660">(</span><span sty=
le> std</span><span style=3D"color:#660">::</span><span style>declval</span=
><span style=3D"color:#660"><</span><span style> </span><span style=3D"c=
olor:#008">self</span><span style> </span><span style=3D"color:#660">>()=
..</span><span style>x </span><span style=3D"color:#660">)</span><span style=
> </span><span style=3D"color:#660">>::</span><span style>type<br>
=A0 =A0 get_x</span><span style=3D"color:#660">(</span><span style> </span>=
<span style=3D"color:#008">self</span><span style> </span><span style=3D"co=
lor:#660">&&</span><span style> o </span><span style=3D"color:#660"=
>)</span><span style><br>
=A0 =A0 =A0 =A0 </span><span style=3D"color:#660">{</span><span style> </sp=
an><span style=3D"color:#008">return</span><span style> std</span><span sty=
le=3D"color:#660">::</span><span style>forward</span><span style=3D"color:#=
660"><</span><span style> </span><span style=3D"color:#008">self</span><=
span style> </span><span style=3D"color:#660">>(</span><span style> o </=
span><span style=3D"color:#660">).</span><span style>x</span><span style=3D=
"color:#660">;</span><span style> </span><span style=3D"color:#660">}</span=
><span style><br>
</span><span style=3D"color:#660">};</span><span style><br></span></div></c=
ode></div><br>If I were you, though, I'd just elaborate the accessor fu=
nctions as before and delegate from the rvalue overload to the lvalue overl=
oad with an explicit <span style=3D"font-family:courier new,monospace">move=
</span>. As you mentioned, const rvalue isn't actually used for anythin=
g, so the <span style=3D"font-family:courier new,monospace">const</span> ov=
erload 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, w=
hich essentially just forwards 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 legitimat=
ely have a custom object model. It looks like OP here might.)<br></div>
</blockquote></div></div></div><div class=3D"HOEnZb"><div class=3D"h5">
<p></p>
-- <br>
=A0<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></div></blockquote></div><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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 />
--089e0112c51c4c912b04e54f67d3--
.
Author: David Krauss <potswa@gmail.com>
Date: Sun, 1 Sep 2013 22:55:54 -0700 (PDT)
Raw View
------=_Part_170_32877432.1378101354166
Content-Type: text/plain; charset=ISO-8859-1
On Sunday, September 1, 2013 3:23:44 PM UTC+8, Artyom Lebedev wrote:
>
> 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.
>
I don't object to accessors unless they're gratuitous. There are use cases
and hence this is the disclaimer is an afterthought. Maurice mentions
variant above.
But do note that there is never an actual need to repeat the algorithm in
the various overloads, as my example demonstrates. If the friend function
is an unpalatable interface, the member overloads to call it will always be
only one line each.
--
---
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_170_32877432.1378101354166
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Sunday, September 1, 2013 3:23:44 PM UTC+8, Art=
yom Lebedev wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"=
ltr"><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(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.=
</div></div></blockquote><div><br>I don't object to accessors unless they'r=
e gratuitous. There are use cases and hence this is the disclaimer is an af=
terthought. Maurice mentions <span style=3D"font-family: courier new,monosp=
ace;">variant</span> above.<br><br>But do note that there is never an actua=
l need to repeat the algorithm in the various overloads, as my example demo=
nstrates. If the friend function is an unpalatable interface, the member ov=
erloads to call it will always be only one line each.<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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_170_32877432.1378101354166--
.
Author: Artyom Lebedev <artyom.lebedev@gmail.com>
Date: Mon, 02 Sep 2013 12:30:37 +0300
Raw View
This is a multi-part message in MIME format.
--------------060100070202020308070903
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
> If the friend function is an unpalatable interface, the member
> overloads to call it will always be only one line each.
Yes, I believe there are workarounds (you have demonstrated one).
However, as every workaround (in contrast with native feature) they are
usually not so nice, and may be cumbersome. What I want, is to introduce
a feature which would make all the mentioned examples simple, short,
nice and readable/understandable. In real world big projects, one of the
most important requirement for the code is readability and therefore
maintainability. Often this is the reason, why C++ is dropped away from
the options of possible project implementation languages - not each and
every average programmer will quickly understand what is done by dozen
of nested type-manipulating templates in your example. And searching for
a bug in such construction, especially if you do not know it is there,
is a real pain (e.g. due to improper types manipulating, reference is
passed and stored somewhere instead of a copy, leading to invalid memory
access later, when the reference is not valid anymore). So I do not see
any reason to discuss workarounds, unless one is really simple and does
not introduce any trade-off between functionality and code
simplicity/readability.
This is your example. I modified it to return reference to stored value
(for example if it was some [] operator which usually returns a
reference) and as you recommended added member functions to hide friend
function. Yes, they are one-liners and do not contain alghorithms but
scale of the disaster is still visible:
> struct S {
> std::string x;
>
> //replace (decltype(std::declval<Self>().x) &) to some more advanced
> //construction, so that lvalue and rvalue reference would properly
> created.
> //I do not even want to do it.
> template<typename Self>
> friend
> typename std::enable_if<std::is_base_of<S, typename
> std::decay<Self>::type>::value,
> decltype(std::declval<Self>().x) &>::type
> _get_x(Self &&self)
> { return std::forward<Self>(self).x; }
>
> std::string &
> Get_x() &
> {
> return _get_x(*this);
> }
>
> const std::string &
> Get_x() const &
> {
> return _get_x(*this);
> }
>
> volatile std::string &
> Get_x() const &
> {
> return _get_x(*this);
> }
>
> const volatile std::string &
> Get_x() const volatile &
> {
> return _get_x(*this);
> }
>
> std::string &&
> Get_x() &&
> {
> return _get_x(std::move(*this));
> }
>
> std::string const &&
> Get_x() const &&
> {
> return _get_x(std::move(*this));
> }
>
> std::string volatile &&
> Get_x() volatile &&
> {
> return _get_x(std::move(*this));
> }
>
> std::string const volatile &&
> Get_x() const volatile &&
> {
> return _get_x(std::move(*this));
> }
> };
And here is a replacement with the new feature:
> struct S {
> std::string x;
>
> template <this Self>
> auto
> Get_x() && ->
> decltype(std::forward<decltype(std::declval<Self>().x)>(std::declval<Self>().x))
> {
> return
> std::forward<decltype(std::declval<Self>().x)>(std::declval<Self>().x);
> }
> };
The templates there are still long enough, but the example is less real
than I previously mentioned. I also repeat the other my thought - 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. So this is
ideological question.
On 2013.09.02. 08:55, David Krauss wrote:
>
>
> On Sunday, September 1, 2013 3:23:44 PM UTC+8, Artyom Lebedev wrote:
>
> 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.
>
>
> I don't object to accessors unless they're gratuitous. There are use
> cases and hence this is the disclaimer is an afterthought. Maurice
> mentions variant above.
>
> But do note that there is never an actual need to repeat the algorithm
> in the various overloads, as my example demonstrates. If the friend
> function is an unpalatable interface, the member overloads to call it
> will always be only one line each.
> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xMlthAq8DWk/unsubscribe.
> To unsubscribe from this group and all its topics, 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/.
--
---
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/.
--------------060100070202020308070903
Content-Type: text/html; charset=ISO-8859-1
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">
<blockquote type="cite">If the friend function is an unpalatable
interface, the member overloads to call it will always be only
one line each.</blockquote>
Yes, I believe there are workarounds (you have demonstrated one).
However, as every workaround (in contrast with native feature)
they are usually not so nice, and may be cumbersome. What I want,
is to introduce a feature which would make all the mentioned
examples simple, short, nice and readable/understandable. In real
world big projects, one of the most important requirement for the
code is readability and therefore maintainability. Often this is
the reason, why C++ is dropped away from the options of possible
project implementation languages - not each and every average
programmer will quickly understand what is done by dozen of nested
type-manipulating templates in your example. And searching for a
bug in such construction, especially if you do not know it is
there, is a real pain (e.g. due to improper types manipulating,
reference is passed and stored somewhere instead of a copy,
leading to invalid memory access later, when the reference is not
valid anymore). So I do not see any reason to discuss workarounds,
unless one is really simple and does not introduce any trade-off
between functionality and code simplicity/readability.<br>
<br>
This is your example. I modified it to return reference to stored
value (for example if it was some [] operator which usually
returns a reference) and as you recommended added member functions
to hide friend function. Yes, they are one-liners and do not
contain alghorithms but scale of the disaster is still visible:<br>
<br>
<blockquote type="cite"><tt>struct S {</tt><tt><br>
</tt><tt> std::string x;</tt><tt><br>
</tt><tt><br>
</tt><tt> //replace (decltype(std::declval<Self>().x)
&) to some more advanced</tt><tt><br>
</tt><tt> //construction, so that lvalue and rvalue reference
would properly created.</tt><tt><br>
</tt><tt> //I do not even want to do it.</tt><tt><br>
</tt><tt> template<typename Self></tt><tt><br>
</tt><tt> friend</tt><tt><br>
</tt><tt> typename std::enable_if<std::is_base_of<S,
typename std::decay<Self>::type>::value,</tt><tt><br>
</tt><tt>
decltype(std::declval<Self>().x) &>::type</tt><tt><br>
</tt><tt> _get_x(Self &&self)</tt><tt><br>
</tt><tt> { return std::forward<Self>(self).x; }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string &</tt><tt><br>
</tt><tt> Get_x() &</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*this);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> const std::string &</tt><tt><br>
</tt><tt> Get_x() const &</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*this);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> volatile std::string &</tt><tt><br>
</tt><tt> Get_x() const &</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*this);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> const volatile std::string &</tt><tt><br>
</tt><tt> Get_x() const volatile &</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*this);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string &&</tt><tt><br>
</tt><tt> Get_x() &&</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(std::move(*this));</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string const &&</tt><tt><br>
</tt><tt> Get_x() const &&</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(std::move(*this));</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string volatile &&</tt><tt><br>
</tt><tt> Get_x() volatile &&</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(std::move(*this));</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string const volatile &&</tt><tt><br>
</tt><tt> Get_x() const volatile &&</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(std::move(*this));</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt>};</tt></blockquote>
And here is a replacement with the new feature:<br>
<blockquote type="cite"><tt>struct S {</tt><tt><br>
</tt><tt> std::string x;</tt><tt><br>
</tt><tt><br>
</tt><tt> </tt><tt>template <this Self></tt><tt><br>
</tt><tt> auto </tt><tt><br>
</tt><tt> Get_x() && ->
decltype(std::forward<decltype(std::declval<Self>().x)>(std::declval<Self>().x))</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return
std::forward<decltype(std::declval<Self>().x)>(std::declval<Self>().x)</tt><tt>;</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt>};</tt><br>
</blockquote>
The templates there are still long enough, but the example is less
real than I previously mentioned. I also repeat the other my
thought - 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. So this is ideological question.<br>
<br>
On 2013.09.02. 08:55, David Krauss wrote:<br>
</div>
<blockquote
cite="mid:f7ffbfd6-432a-4d1e-82e9-dd76da05750a@isocpp.org"
type="cite">
<div dir="ltr"><br>
<br>
On Sunday, September 1, 2013 3:23:44 PM UTC+8, Artyom Lebedev
wrote:
<blockquote class="gmail_quote" style="margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div dir="ltr">
<blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px
solid rgb(204,204,204);padding-left:1ex"
class="gmail_quote">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.<br>
</blockquote>
<div>Probably you a bit misunderstood the idea. It by no
means related to accessor functions.</div>
</div>
</blockquote>
<div><br>
I don't object to accessors unless they're gratuitous. There
are use cases and hence this is the disclaimer is an
afterthought. Maurice mentions <span style="font-family:
courier new,monospace;">variant</span> above.<br>
<br>
But do note that there is never an actual need to repeat the
algorithm in the various overloads, as my example
demonstrates. If the friend function is an unpalatable
interface, the member overloads to call it will always be only
one line each.<br>
</div>
</div>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to a topic in
the Google Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a moz-do-not-send="true"
href="https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xMlthAq8DWk/unsubscribe">https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xMlthAq8DWk/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email
to <a class="moz-txt-link-abbreviated" href="mailto:std-proposals+unsubscribe@isocpp.org">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a class="moz-txt-link-abbreviated" href="mailto:std-proposals@isocpp.org">std-proposals@isocpp.org</a>.<br>
Visit this group at <a moz-do-not-send="true"
href="http://groups.google.com/a/isocpp.org/group/std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/</a>.<br>
</blockquote>
<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email 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="http://groups.google.com/a/isocpp.org/group/std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/</a>.<br />
--------------060100070202020308070903--
.
Author: David Krauss <potswa@gmail.com>
Date: Mon, 2 Sep 2013 05:14:03 -0700 (PDT)
Raw View
------=_Part_2585_15404092.1378124043265
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, September 2, 2013 5:30:37 PM UTC+8, Artyom Lebedev wrote:
>
> =20
> struct S {
> std::string x;
>
> //replace (decltype(std::declval<Self>().x) &) to some more advanced
> //construction, so that lvalue and rvalue reference would properly=20
> created.
>
> No, adding the & undermines the preceding decltype. You might as well=20
write int &. And that bit of type arithmetic is common to your example, in=
=20
which it's similarly noisy but expressed slightly differently. Anyway we=20
can both use deduced return type. And unless this is a public interface=20
with a name reused by another interface, there is actually no need for=20
SFINAE, either. So it starts to look a lot more like your example.
> template<typename Self>
> friend
> decltype( auto )
> _get_x(Self &&self)
> { return std::forward<Self>(self).x; }
>
> std::string &
> Get_x() &
> {
> return _get_x(*this);
> }
>
> Recall that const && and non-const && have same semantics. You don't need=
=20
to ref-qualify the const case.=20
> const std::string &
> Get_x() const
> {
> return _get_x(*this);
> }
>
> Are you supplying the volatile overloads just because the volatile=20
qualifier exists? You must realize it is only used for device drivers, and=
=20
applying it to a high-level object cannot have useful effects. So, cutting=
=20
those=85
> std::string &&
> Get_x() &&
> {
> return _get_x(std::move(*this));
> }
>
> };
>
> See? That wasn't so bad.
Ultimately the motivation for your case is providing the complete set of 4=
=20
cv-qualifications x 2 ref-qualifications, but in practice only 3 count. If=
=20
you are so obsessed, or really intend to write high-level template code=20
over volatile storage (where each memory access is significant so you can't=
=20
touch anything accidentally), then copy-paste-tweaking 8 one-liners will be=
=20
your just deserts.
--=20
---=20
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 e=
mail 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-proposa=
ls/.
------=_Part_2585_15404092.1378124043265
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Monday, September 2, 2013 5:30:37 PM UTC+8, Art=
yom Lebedev wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div><br>
<blockquote type=3D"cite"><tt>struct S {</tt><tt><br>
</tt><tt> std::string x;</tt><tt><br>
</tt><tt><br>
</tt><tt> //replace (decltype(std::declval<Sel=
f>()<wbr>.x)
&) to some more advanced</tt><tt><br>
</tt><tt> //construction, so that lvalue and rval=
ue reference
would properly created.</tt><tt><br></tt></blockquote></div></div=
></blockquote><div>No, adding the <span style=3D"font-family: courier new,m=
onospace;">&</span> undermines the preceding <span style=3D"font-family=
: courier new,monospace;">decltype</span>. You might as well write <span st=
yle=3D"font-family: courier new,monospace;">int &</span>. And that bit =
of type arithmetic is common to your example, in which it's similarly noisy=
but expressed slightly differently. Anyway we can both use deduced return =
type. And unless this is a public interface with a name reused by another i=
nterface, there is actually no need for SFINAE, either. So it starts to loo=
k a lot more like your example.<br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000"><div><blockquote type=
=3D"cite"><tt>
</tt><tt> template<typename Self></tt><tt><=
br>
</tt><tt> friend</tt><tt><br>
</tt><tt> decltype( auto )</tt><tt><br>
</tt><tt> _get_x(Self &&self)</tt><tt><br=
>
</tt><tt> { return std::forward<Self>(self)=
..x; }</tt><tt><br>
</tt><tt><br>
</tt><tt> std::string &</tt><tt><br>
</tt><tt> Get_x() &</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*=
this);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br></tt></blockquote></div></div></blockquote><div>Recall=
that const && and non-const && have same semantics. You do=
n't need to ref-qualify the const case. <br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000"><div><blockqu=
ote type=3D"cite"><tt>
</tt><tt> const std::string &</tt><tt><br>
</tt><tt> Get_x() const</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(*=
this);</tt><tt><br>
</tt><tt> }</tt><tt><br></tt></blockquote></div><=
/div></blockquote><div>Are you supplying the volatile overloads just becaus=
e the volatile qualifier exists? You must realize it is only used for devic=
e drivers, and applying it to a high-level object cannot have useful effect=
s. So, cutting those=85<br></div><blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;"><div bgcolor=3D"#FFFFFF" text=3D"#000000"><div><blockquote type=3D"cite"=
><tt>
</tt><tt> std::string &&</tt><tt><br>
</tt><tt> Get_x() &&</tt><tt><br>
</tt><tt> {</tt><tt><br>
</tt><tt> return _get_x(s=
td::move(*this));</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt><br>
</tt><tt>};</tt></blockquote></div></div></blockquote><div>See? Tha=
t wasn't so bad.<br><br>Ultimately the motivation for your case is providin=
g the complete set of 4 cv-qualifications x 2 ref-qualifications, but in pr=
actice only 3 count. If you are so obsessed, or really intend to write high=
-level template code over volatile storage (where each memory access is sig=
nificant so you can't touch anything accidentally), then copy-paste-tweakin=
g 8 one-liners will be your just deserts.<br><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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_2585_15404092.1378124043265--
.