Topic: Extend defition of INVOKE for member pointers to


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 13:25:16 -0700 (PDT)
Raw View
------=_Part_539_6656093.1372969516776
Content-Type: multipart/alternative;
 boundary="----=_Part_540_32041913.1372969516776"

------=_Part_540_32041913.1372969516776
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

The current definition of INVOKE for member pointers to class (lets named=
=20
it C) doesn't not allow to use as the first arguments types convertible to=
=20
C as the first argument - the most common example would be the reference=20
wrapper (see LWG Issue #2219)<http://www.open-std.org/jtc1/sc22/wg21/docs/l=
wg-active.html#2219>.=20
The solution proposed in the issue add supports only to the=20
reference_wrapper, so user defined types with such conversions will still=
=20
not work (ex. boost::reference_wrapper).

I would like to propose the different  solutions that will cover support=20
for classes converitble to C or references to C. The wording is a bit rough=
=20
at this point, but I think is clearly stating the intent.

Viable reference types TR for member pointer p of type M T::* are:
  - T&, T&& if M is not function type
  - T cv&, T cv&& if M is function type without ref-qualification and with=
=20
CV-qualification cv
  - T cv ref if M is function type without ref-qualification ref and with=
=20
CV-qualification cv

Define INVOKE (f, t1, t2, ..., tN) as follows:
=97 (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and t1 is convertible to TR where TR is viable=20
reference type for f.
=97 (static_cast<TR>(*t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and *t1 is convertible to TR where TR is viable=20
reference type for f.
=97 static_cast<TR>(t1).*f when N =3D=3D 1 and f is a pointer to member dat=
a of a=20
class T and t1 is convertible to TR where TR is viable reference type for f=
..
=97 static_cast<TR>(*t1).*f when N =3D=3D 1 and f is a pointer to member da=
ta of=20
a class Tand t1 is convertible to TR where TR is viable reference type for=
=20
f.
=97 f(t1, t2, ..., tN) in all other cases.
The should be additional statement that defines that if for member pointer,=
=20
more than one options matches, then INVOKE should be ill-formed. No=20
preference. Also point about conversion to TR covers references to T and=20
its deliver classes. I don't really know how to define it.

If the new definition will be accepted then, the behavior of the INVOKE=20
will change for the classes that defines both operator* returning class C=
=20
and having conversion operator to C, example:
struct weird
{
  C& operator*();
  operator C();
};
But for this cases the problem wont compile, so now silent behavior changes=
=20
would be introduced.

In the attachment I included proof-of-concept implementation of invoke=20
function.

--=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_540_32041913.1372969516776
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

The current definition of INVOKE for member pointers to class (lets named i=
t C) doesn't not allow to use as the first arguments types convertible to C=
 as the first argument - the most common example would be the reference wra=
pper (see <a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active=
..html#2219">LWG Issue #2219)</a>. The solution proposed in the issue add su=
pports only to the reference_wrapper, so user defined types with such conve=
rsions will still not work (ex. boost::reference_wrapper).<br><br>I would l=
ike to propose the different&nbsp; solutions that will cover support for cl=
asses converitble to C or references to C. The wording is a bit rough at th=
is point, but I think is clearly stating the intent.<br><br><span style=3D"=
font-family: courier new,monospace;">Viable reference types TR for member p=
ointer p of type M T::* are:<br>&nbsp; - T&amp;, T&amp;&amp; if M is not fu=
nction type<br>&nbsp; - T cv&amp;, T cv&amp;&amp; if M is function type wit=
hout ref-qualification and with CV-qualification cv<br>&nbsp; - T cv ref  i=
f M is function type without ref-qualification ref and with CV-qualificatio=
n cv<br><br>Define INVOKE (f, t1, t2, ..., tN) as follows:<br>=97 (static_c=
ast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a member function=
 of a class T and t1 is convertible to TR where TR is viable reference type=
 for f.<br>=97 (static_cast&lt;TR&gt;(*t1).*f)(t2, ..., tN) when f is a poi=
nter to a=20
member function of a class T and *t1 is convertible to TR where TR is=20
viable reference type for f.<br>=97 static_cast&lt;TR&gt;(t1).*f when N =3D=
=3D 1 and f is a pointer to member data of a class T  and t1 is convertible=
 to TR where TR is viable reference type for f.<br>=97 static_cast&lt;TR&gt=
;(*t1).*f when N =3D=3D 1 and f is a pointer to member data of a class Tand=
 t1 is convertible to TR where TR is viable reference type for f.<br>=97 f(=
t1, t2, ..., tN) in all other cases.</span><br>The should be additional sta=
tement that defines that if for member pointer, more than one options match=
es, then INVOKE should be ill-formed. No preference. Also point about conve=
rsion to TR covers references to T and its deliver classes. I don't really =
know how to define it.<br><br>If the new definition will be accepted then, =
the behavior of the INVOKE will change for the classes that defines both op=
erator* returning class C and having conversion operator to C, example:<br>=
<span style=3D"font-family: courier new,monospace;">struct weird<br>{<br>&n=
bsp; C&amp; operator*();<br>&nbsp; operator C();<br>};</span><br>But for th=
is cases the problem wont compile, so now silent behavior changes would be =
introduced.<br><br>In the attachment I included proof-of-concept implementa=
tion of invoke function.<br>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_540_32041913.1372969516776--
------=_Part_539_6656093.1372969516776
Content-Type: text/x-c++src; charset=US-ASCII; name=invoke.cpp
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=invoke.cpp
X-Attachment-Id: 2c79c0aa-a8bb-4b49-a9ff-e3f7b448b77d
Content-ID: <2c79c0aa-a8bb-4b49-a9ff-e3f7b448b77d>

#include <memory>
#include <type_traits>

template<typename T>
struct target_class
{
  typedef void type;
};

template<typename Class, typename Member>
struct target_class<Member Class::*>
{
  typedef Class type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...)>
{
  typedef Class type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const>
{
  typedef Class const type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) volatile>
{
  typedef Class volatile type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const volatile>
{
  typedef Class const volatile type;
};


template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) &>
{
  typedef Class& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const&>
{
  typedef Class const& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) volatile&>
{
  typedef Class volatile& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const volatile&>
{
  typedef Class const volatile type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) &&>
{
  typedef Class&& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const&&>
{
  typedef Class const&& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) volatile&&>
{
  typedef Class volatile&& type;
};

template<typename Class, typename Ret, typename... Args>
struct target_class<Ret (Class::*)(Args...) const volatile&&>
{
  typedef Class const volatile&& type;
};

template<typename T>
using target_class_t = typename target_class<T>::type;

template<typename T>
inline T& as_ref(T& t) { return t; }

template<typename T>
inline typename std::enable_if<
  !std::is_reference<T>::value,
  T&&
>::type as_ref(T&& t) { return std::forward<T>(t); }

template<typename T, typename U>
struct is_compatible_with_member_pointer_of
  : public std::integral_constant<bool,
      std::is_convertible<T, U&>::value ||
      std::is_convertible<T, U const&>::value ||
      std::is_convertible<T, U&&>::value
    >
{};

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype((as_ref<target_class_t<Functor>>(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (as_ref<target_class_t<Functor>>(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype((as_ref<target_class_t<Functor>>(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (as_ref<target_class_t<Functor>>(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(as_ref<target_class_t<Functor>>(std::forward<Object>(object)).*functor)
      >::type
{
  return as_ref<target_class_t<Functor>>(std::forward<Object>(object)).*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(as_ref<target_class_t<Functor>>(*std::forward<Object>(object)).*functor)
      >::type
{
  return as_ref<target_class_t<Functor>>(*std::forward<Object>(object)).*functor;
}

template<typename Functor, typename... Args>
inline auto invoke(Functor&& functor, Args&&... args)
  ->  typename std::enable_if<
        !std::is_member_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
      >::type
{
  return std::forward<Functor>(functor)(std::forward<Args>(args)...);
}

struct A
{
  void f() const {}
  void f_l() & {}
  int m;
};

struct B
{
  operator A() { return A{}; }
};

int main()
{
  A a;
  B b;
  std::unique_ptr<A> ap;
  static_assert(is_compatible_with_member_pointer_of<B&, A>::value, "check values");

  invoke(&A::f, A{});
  invoke(&A::f, a);
  invoke(&A::f, ap);
  invoke(&A::f, std::ref(a));
  invoke(&A::f, b);

  invoke(&A::f_l, A{});
  invoke(&A::f_l, a);
  invoke(&A::f_l, ap);
  invoke(&A::f_l, std::ref(a));
  invoke(&A::f_l, b);

  int&& i = invoke(&A::m, A{});
  invoke(&A::m, a);
  invoke(&A::m, ap);
  invoke(&A::m, std::ref(a));
  invoke(&A::m, b);

  invoke([](int) {}, 1);

}
------=_Part_539_6656093.1372969516776--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 01:01:17 +0300
Raw View
--14dae94ee3e7b9eec404e0b6b7dc
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

On 4 July 2013 23:25, <tomaszkam@gmail.com> wrote:

> The current definition of INVOKE for member pointers to class (lets named
> it C) doesn't not allow to use as the first arguments types convertible t=
o
> C as the first argument - the most common example would be the reference
> wrapper (see LWG Issue #2219)<http://www.open-std.org/jtc1/sc22/wg21/docs=
/lwg-active.html#2219>.
> The solution proposed in the issue add supports only to the
> reference_wrapper, so user defined types with such conversions will still
> not work (ex. boost::reference_wrapper).
>
> I would like to propose the different  solutions that will cover support
> for classes converitble to C or references to C. The wording is a bit rou=
gh
> at this point, but I think is clearly stating the intent.
>
> Viable reference types TR for member pointer p of type M T::* are:
>   - T&, T&& if M is not function type
>   - T cv&, T cv&& if M is function type without ref-qualification and wit=
h
> CV-qualification cv
>   - T cv ref if M is function type without ref-qualification ref and with
> CV-qualification cv
>

The last one should say "with ref-qualification", not "without
ref-qualification".


>
> Define INVOKE (f, t1, t2, ..., tN) as follows:
> =97 (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member
> function of a class T and t1 is convertible to TR where TR is viable
> reference type for f.
>

I wonder how you plan to prevent these from downcasting in a class
hierarchy. This wording won't do it, and I can't
see such prevention in the proof-of-concept implementation either.

If the new definition will be accepted then, the behavior of the INVOKE
> will change for the classes that defines both operator* returning class C
> and having conversion operator to C, example:
> struct weird
> {
>   C& operator*();
>   operator C();
> };
> But for this cases the problem wont compile, so now silent behavior
> changes would be introduced.
>

I don't find such a class weird. Does the behavior change so that things
that used to be valid are no longer
valid, then? Is this weird-struct ok for INVOKE under the current rules,
but invalid under your proposal?

--=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/.



--14dae94ee3e7b9eec404e0b6b7dc
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 4 July 2013 23:25,  <span dir=3D"ltr">&lt;<a href=3D"mailto:toma=
szkam@gmail.com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote=
:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-le=
ft:1px #ccc solid;padding-left:1ex">
The current definition of INVOKE for member pointers to class (lets named i=
t C) doesn&#39;t not allow to use as the first arguments types convertible =
to C as the first argument - the most common example would be the reference=
 wrapper (see <a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-ac=
tive.html#2219" target=3D"_blank">LWG Issue #2219)</a>. The solution propos=
ed in the issue add supports only to the reference_wrapper, so user defined=
 types with such conversions will still not work (ex. boost::reference_wrap=
per).<br>
<br>I would like to propose the different=A0 solutions that will cover supp=
ort for classes converitble to C or references to C. The wording is a bit r=
ough at this point, but I think is clearly stating the intent.<br><br><span=
 style=3D"font-family:courier new,monospace">Viable reference types TR for =
member pointer p of type M T::* are:<br>
=A0 - T&amp;, T&amp;&amp; if M is not function type<br>=A0 - T cv&amp;, T c=
v&amp;&amp; if M is function type without ref-qualification and with CV-qua=
lification cv<br>=A0 - T cv ref  if M is function type without ref-qualific=
ation ref and with CV-qualification cv<br>
</span></blockquote><div><br></div><div>The last one should say &quot;with =
ref-qualification&quot;, not &quot;without ref-qualification&quot;.<br>=A0<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;borde=
r-left:1px #ccc solid;padding-left:1ex">
<span style=3D"font-family:courier new,monospace"><br>Define INVOKE (f, t1,=
 t2, ..., tN) as follows:<br>=97 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN=
) when f is a pointer to a member function of a class T and t1 is convertib=
le to TR where TR is viable reference type for f.<br>
</span></blockquote><div><br></div><div>I wonder how you plan to prevent th=
ese from downcasting in a class hierarchy. This wording won&#39;t do it, an=
d I can&#39;t<br>see such prevention in the proof-of-concept implementation=
 either.<br>
<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bord=
er-left:1px #ccc solid;padding-left:1ex">If the new definition will be acce=
pted then, the behavior of the INVOKE will change for the classes that defi=
nes both operator* returning class C and having conversion operator to C, e=
xample:<br>
<span style=3D"font-family:courier new,monospace">struct weird<br>{<br>=A0 =
C&amp; operator*();<br>=A0 operator C();<br>};</span><br>But for this cases=
 the problem wont compile, so now silent behavior changes would be introduc=
ed.<br>
</blockquote><div><br></div><div>I don&#39;t find such a class weird. Does =
the behavior change so that things that used to be valid are no longer<br>v=
alid, then? Is this weird-struct ok for INVOKE under the current rules, but=
 invalid under your proposal?<br>
<br></div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--14dae94ee3e7b9eec404e0b6b7dc--

.


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 15:33:26 -0700 (PDT)
Raw View
------=_Part_2075_15396837.1372977206879
Content-Type: multipart/alternative;
 boundary="----=_Part_2076_2860258.1372977206879"

------=_Part_2076_2860258.1372977206879
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

Firstly, in the wording the I improperly specified the viable references=20
for member object pointer type (missing cv):
Viable reference types TR for member pointer p of type M T::* are:
  - T cv&, T cv&& if M is not function type for all possible=20
CV-qualifications
  - T cv&, T cv&& if M is function type without ref-qualification and with=
=20
CV-qualification cv
  - T cv ref if M is function type with ref-qualification ref and with=20
CV-qualification cv

Define INVOKE (f, t1, t2, ..., tN) as follows:
-- (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=20
function of a class T and t1 is convertible to TR where TR is viable=20
reference type for f.
-- (static_cast<TR>(*t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and *t1 is convertible to TR where TR is viable=20
reference type for f.
-- static_cast<TR>(t1).*f when N =3D=3D 1 and f is a pointer to member data=
 of a=20
class T and t1 is convertible to TR where TR is viable reference type for f=
..
-- static_cast<TR>(*t1).*f when N =3D=3D 1 and f is a pointer to member dat=
a of=20
a class Tand t1 is convertible to TR where TR is viable reference type for=
=20
f.
-- f(t1, t2, ..., tN) in all other cases.
Also I attach changed implementation of proof-of-concept.


W dniu pi=B1tek, 5 lipca 2013 00:01:17 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:

>
>> Viable reference types TR for member pointer p of type M T::* are:
>>   - T&, T&& if M is not function type
>>   - T cv&, T cv&& if M is function type without ref-qualification and=20
>> with CV-qualification cv
>>   - T cv ref if M is function type without ref-qualification ref and wit=
h=20
>> CV-qualification cv
>>
>
> The last one should say "with ref-qualification", not "without=20
> ref-qualification".
> =20
>
Ok.
=20

>
>> Define INVOKE (f, t1, t2, ..., tN) as follows:
>> -- (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
>> function of a class T and t1 is convertible to TR where TR is viable=20
>> reference type for f.
>>
> In the case of downcast t1 (being a base class of T) wouldn't be=20
convertible (implictly) to any of TR. The implementation do the same things=
..
=20

>
> If the new definition will be accepted then, the behavior of the INVOKE=
=20
>> will change for the classes that defines both operator* returning class =
C=20
>> and having conversion operator to C, example:
>> struct weird
>> {
>>   C& operator*();
>>   operator C();
>> };
>> But for this cases the problem wont compile, so now silent behavior=20
>> changes would be introduced.
>>
>
> I don't find such a class weird. Does the behavior change so that things=
=20
> that used to be valid are no longer
> valid, then? Is this weird-struct ok for INVOKE under the current rules,=
=20
> but invalid under your proposal?
>
> For current wording this kind of classes will go trough the (*t).*f path.=
=20
In my proposed implementation there will be dis-ambiguity between path=20
using conversion operator and the path going via operator*, so it will be=
=20
no longer valid. Also I find such weird, because they merge the=20
pointer-to-C semantics with a obejct-of-type-C semantics, so in my opinion=
=20
there is nothing wrong to make them ambiguous in cases of calling member=20
function of C.
=20

--=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_2076_2860258.1372977206879
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

Firstly, in the wording the I improperly specified the viable references fo=
r member object pointer type (missing cv):<br><span style=3D"font-family: c=
ourier new,monospace;">Viable reference types TR for member pointer p of ty=
pe M T::* are:<br>&nbsp; - T cv&amp;, T cv&amp;&amp; if M is not function t=
ype for all possible CV-qualifications<br>&nbsp; - T cv&amp;, T cv&amp;&amp=
; if M is function type without ref-qualification and with CV-qualification=
 cv<br>&nbsp; - T cv ref  if M is function type with ref-qualification ref =
and with CV-qualification cv<br><br>Define INVOKE (f, t1, t2, ..., tN) as f=
ollows:<br>&mdash;
 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and t1 is convertible to TR where TR is=20
viable reference type for f.<br>&mdash; (static_cast&lt;TR&gt;(*t1).*f)(t2,=
 ..., tN) when f is a pointer to a=20
member function of a class T and *t1 is convertible to TR where TR is=20
viable reference type for f.<br>&mdash; static_cast&lt;TR&gt;(t1).*f when N=
 =3D=3D
 1 and f is a pointer to member data of a class T  and t1 is convertible
 to TR where TR is viable reference type for f.<br>&mdash;=20
static_cast&lt;TR&gt;(*t1).*f when N =3D=3D 1 and f is a pointer to member=
=20
data of a class Tand t1 is convertible to TR where TR is viable=20
reference type for f.<br>&mdash; f(t1, t2, ..., tN) in all other cases.</sp=
an><br>Also I attach changed implementation of proof-of-concept.<br><br><br=
>W dniu pi=B1tek, 5 lipca 2013 00:01:17 UTC+2 u=BFytkownik Ville Voutilaine=
n napisa=B3:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"lt=
r"><div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br><spa=
n style=3D"font-family:courier new,monospace">Viable reference types TR for=
 member pointer p of type M T::* are:<br>
&nbsp; - T&amp;, T&amp;&amp; if M is not function type<br>&nbsp; - T cv&amp=
;, T cv&amp;&amp; if M is function type without ref-qualification and with =
CV-qualification cv<br>&nbsp; - T cv ref  if M is function type without ref=
-qualification ref and with CV-qualification cv<br>
</span></blockquote><div><br></div><div>The last one should say "with ref-q=
ualification", not "without ref-qualification".<br>&nbsp;<br></div></div></=
div></div></blockquote><div>Ok.<br>&nbsp;</div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><div></di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex">
<span style=3D"font-family:courier new,monospace"><br>Define INVOKE (f, t1,=
 t2, ..., tN) as follows:<br>&mdash; (static_cast&lt;TR&gt;(t1).*f)(t2, ...=
, tN) when f is a pointer to a member function of a class T and t1 is conve=
rtible to TR where TR is viable reference type for f.</span><br></blockquot=
e></div></div></div></blockquote><div>In the case of downcast t1 (being a b=
ase class of T) wouldn't be convertible (implictly) to any of TR. The imple=
mentation do the same things.<br>&nbsp;</div><blockquote class=3D"gmail_quo=
te" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddi=
ng-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><blockquote=
 class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc soli=
d;padding-left:1ex"></blockquote><div>
<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bord=
er-left:1px #ccc solid;padding-left:1ex">If the new definition will be acce=
pted then, the behavior of the INVOKE will change for the classes that defi=
nes both operator* returning class C and having conversion operator to C, e=
xample:<br>
<span style=3D"font-family:courier new,monospace">struct weird<br>{<br>&nbs=
p; C&amp; operator*();<br>&nbsp; operator C();<br>};</span><br>But for this=
 cases the problem wont compile, so now silent behavior changes would be in=
troduced.<br>
</blockquote><div><br></div><div>I don't find such a class weird. Does the =
behavior change so that things that used to be valid are no longer<br>valid=
, then? Is this weird-struct ok for INVOKE under the current rules, but inv=
alid under your proposal?<br>
<br></div></div></div></div></blockquote><div>For current wording this kind=
 of classes will go trough the (*t).*f path. In my proposed implementation =
there will be dis-ambiguity between path using conversion operator and the =
path going via operator*, so it will be no longer valid. Also I find such w=
eird, because they merge the pointer-to-C semantics with a obejct-of-type-C=
 semantics, so in my opinion there is nothing wrong to make them ambiguous =
in cases of calling member function of C.<br></div><div>&nbsp;</div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_2076_2860258.1372977206879--
------=_Part_2075_15396837.1372977206879
Content-Type: text/x-c++src; charset=US-ASCII; name=invoke.cpp
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=invoke.cpp
X-Attachment-Id: 6049e808-0861-4e4e-bf10-fb47fb144cc6
Content-ID: <6049e808-0861-4e4e-bf10-fb47fb144cc6>

#include <memory>
#include <type_traits>

template<typename Class, typename Member>
struct to_viable_ref_functor
{
  Class& operator()(Class& c)
  {
     return c;
  }

  Class&& operator()(Class&& c)
  {
     return std::move(c);
  }

  Class const& operator()(Class const& c)
  {
     return c;
  }

  Class const&& operator()(Class const&& c)
  {
     return std::move(c);
  }

  Class volatile& operator()(Class volatile& c)
  {
     return c;
  }

  Class volatile&& operator()(Class volatile&& c)
  {
     return std::move(c);
  }

  Class const volatile& operator()(Class const volatile& c)
  {
     return c;
  }

  Class const volatile&& operator()(Class const volatile&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...)>
{
  Class& operator()(Class& c)
  {
     return c;
  }

  Class&& operator()(Class&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const>
{
  Class const& operator()(Class const& c)
  {
     return c;
  }

  Class const&& operator()(Class const&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) volatile>
{
  Class volatile& operator()(Class volatile& c)
  {
     return c;
  }

  Class volatile&& operator()(Class volatile&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const volatile>
{
  Class const volatile& operator()(Class const volatile& c)
  {
     return c;
  }

  Class const volatile&& operator()(Class const volatile&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...)&>
{
  Class& operator()(Class& c)
  {
     return c;
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const&>
{
  Class const& operator()(Class const& c)
  {
     return c;
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) volatile&>
{
  Class volatile& operator()(Class volatile& c)
  {
     return c;
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const volatile&>
{
  Class const volatile& operator()(Class const volatile& c)
  {
     return c;
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...)&&>
{
  Class&& operator()(Class&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const&&>
{
  Class const&& operator()(Class const&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) volatile&&>
{
  Class volatile&& operator()(Class volatile&& c)
  {
     return std::move(c);
  }
};

template<typename Class, typename Ret, typename... Args>
struct to_viable_ref_functor<Class, Ret(Args...) const volatile&&>
{
  Class const volatile&& operator()(Class const volatile&& c)
  {
     return std::move(c);
  }
};

template<typename T>
struct to_viable_ref;

template<typename Class, typename Member>
struct to_viable_ref<Member Class::*> : to_viable_ref_functor<Class, Member>
{};

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor;
}

template<typename Functor, typename... Args>
inline auto invoke(Functor&& functor, Args&&... args)
  ->  typename std::enable_if<
        !std::is_member_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
      >::type
{
  return std::forward<Functor>(functor)(std::forward<Args>(args)...);
}

struct A
{
  void f() const {}
  void f_l() & {}
  int m;
};

struct B
{
  operator A() { return A{}; }
};

struct weird
{
  A operator*() { return A{}; }
  operator A() { return A{}; }
};

int main()
{
  A a;
  B b;
  std::unique_ptr<A> ap;

  invoke(&A::f, A{});
  //invoke(&A::f, weird{});
  invoke(&A::f, a);
  invoke(&A::f, ap);
  invoke(&A::f, std::ref(a));
  invoke(&A::f, b);

  invoke(&A::f_l, A{});
  invoke(&A::f_l, a);
  invoke(&A::f_l, ap);
  invoke(&A::f_l, std::ref(a));
  invoke(&A::f_l, b);

  int&& i = invoke(&A::m, A{});
  invoke(&A::m, a);
  invoke(&A::m, ap);
  invoke(&A::m, std::ref(a));
  invoke(&A::m, b);

  invoke([](int) {}, 1);

}
------=_Part_2075_15396837.1372977206879--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 01:52:31 +0300
Raw View
--047d7bdc9396f424bc04e0b76e99
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

On 5 July 2013 01:33, <tomaszkam@gmail.com> wrote:


> Define INVOKE (f, t1, t2, ..., tN) as follows:
>>> =97 (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a memb=
er
>>> function of a class T and t1 is convertible to TR where TR is viable
>>> reference type for f.
>>>
>> In the case of downcast t1 (being a base class of T) wouldn't be
> convertible (implictly) to any of TR. The implementation do the same thin=
gs.
>

Thanks. I am not well-versed with INVOKE, it would be helpful if it said
somewhere that the conversion must be
implicit. Specifying it in terms of static_cast suggests otherwise, so
perhaps that could be said directly
in the wording?


For current wording this kind of classes will go trough the (*t).*f path.
> In my proposed implementation there will be dis-ambiguity between path
> using conversion operator and the path going via operator*, so it will be
> no longer valid. Also I find such weird, because they merge the
> pointer-to-C semantics with a obejct-of-type-C semantics, so in my opinio=
n
> there is nothing wrong to make them ambiguous in cases of calling member
> function of C.
>
>
>
Well, I think going through the (*t).*f path makes a lot of sense, compared
to going via the conversion operator
which makes no sense to me, because it creates a temporary anyway. Having
such a nonsense conversion
be ambiguous with the operator* thus doesn't make much sense to me either.
In other words, I have a lot
of preference for operator* being preferred to conversion functions. I also
happen to think that having this
conversion support is worth breaking that kind of classes, because as I
said, I don't find them weird. The
standard may not include any such classes, but I have seen such code in the
wild.

--=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/.



--047d7bdc9396f424bc04e0b76e99
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 01:33,  <span dir=3D"ltr">&lt;<a href=3D"mailto:toma=
szkam@gmail.com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote=
:<br><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><br><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">
<div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span style=
=3D"font-family:courier new,monospace">Define INVOKE (f, t1, t2, ..., tN) a=
s follows:<br>
=97 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a me=
mber function of a class T and t1 is convertible to TR where TR is viable r=
eference type for f.</span><br></blockquote></div></div></div></blockquote>
<div>In the case of downcast t1 (being a base class of T) wouldn&#39;t be c=
onvertible (implictly) to any of TR. The implementation do the same things.=
<br></div></blockquote><div><br></div><div>Thanks. I am not well-versed wit=
h INVOKE, it would be helpful if it said somewhere that the conversion must=
 be<br>
</div><div class=3D"gmail_quote">implicit. Specifying it in terms of static=
_cast suggests otherwise, so perhaps that could be said directly<br>in the =
wording?<br><br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>For current wording this kind of classes will go trough the (*t).*f pa=
th. In my proposed implementation there will be dis-ambiguity between path =
using conversion operator and the path going via operator*, so it will be n=
o longer valid. Also I find such weird, because they merge the pointer-to-C=
 semantics with a obejct-of-type-C semantics, so in my opinion there is not=
hing wrong to make them ambiguous in cases of calling member function of C.=
<br>
</div><div class=3D"HOEnZb"><div class=3D"h5"><div><br><br></div></div></di=
v></blockquote><div><br></div><div>Well, I think going through the (*t).*f =
path makes a lot of sense, compared to going via the conversion operator<br=
>
which makes no sense to me, because it creates a temporary anyway. Having s=
uch a nonsense conversion<br></div><div>be ambiguous with the operator* thu=
s doesn&#39;t make much sense to me either. In other words, I have a lot<br=
>
</div><div>of preference for operator* being preferred to conversion functi=
ons. I also happen to think that having this<br></div><div>conversion suppo=
rt is worth breaking that kind of classes, because as I said, I don&#39;t f=
ind them weird. The<br>
standard may not include any such classes, but I have seen such code in the=
 wild.<br></div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--047d7bdc9396f424bc04e0b76e99--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 02:02:40 +0300
Raw View
--20cf303346513c36f704e0b79301
Content-Type: text/plain; charset=ISO-8859-1

On 5 July 2013 01:52, Ville Voutilainen <ville.voutilainen@gmail.com> wrote:

> of preference for operator* being preferred to conversion functions. I
> also happen to think that having this
> conversion support is worth breaking that kind of classes, because as I
> said, I don't find them weird. The
>
>
>
That bit is missing a "not". :) I do NOT think having this convertibility
support is worth the breakage,
so I think it would be beneficial to avoid the breakage to gain this
convertibility support.

--

---
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/.



--20cf303346513c36f704e0b79301
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 01:52, Ville Voutilainen <span dir=3D"ltr">&lt;<a hr=
ef=3D"mailto:ville.voutilainen@gmail.com" target=3D"_blank">ville.voutilain=
en@gmail.com</a>&gt;</span> wrote:<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">of preference for operator*=
 being preferred to conversion functions. I also happen to think that havin=
g this<br>
<div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>conversion suppo=
rt is worth breaking that kind of classes, because as I said, I don&#39;t f=
ind them weird. The<br>
<br><br></div></div></div></div></blockquote><div><br></div><div>That bit i=
s missing a &quot;not&quot;. :) I do NOT think having this convertibility s=
upport is worth the breakage,<br>so I think it would be beneficial to avoid=
 the breakage to gain this convertibility support.=A0 <br>
</div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--20cf303346513c36f704e0b79301--

.


Author: Gabriel Dos Reis <gdr@axiomatics.org>
Date: Thu, 04 Jul 2013 18:08:22 -0500
Raw View
Ville Voutilainen <ville.voutilainen@gmail.com> writes:

[...]

|     If the new definition will be accepted then, the behavior of the INVO=
KE
|     will change for the classes that defines both operator* returning cla=
ss C
|     and having conversion operator to C, example:
|     struct weird
|     {
|     =A0 C& operator*();
|     =A0 operator C();
|     };
|     But for this cases the problem wont compile, so now silent behavior c=
hanges
|     would be introduced.
|=20
|=20
| I don't find such a class weird.

Indeed, it isn't.  It isn't far from a wrapper class that turns an
integer into an iterator.

-- Gaby

--=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/.



.


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 16:18:28 -0700 (PDT)
Raw View
------=_Part_591_11492938.1372979908593
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable



W dniu pi=B1tek, 5 lipca 2013 00:52:31 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:
>
>
>
>
> On 5 July 2013 01:33, <toma...@gmail.com <javascript:>> wrote:
>
>
>> Define INVOKE (f, t1, t2, ..., tN) as follows:
>>>> -- (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a memb=
er=20
>>>> function of a class T and t1 is convertible to TR where TR is viable=
=20
>>>> reference type for f.
>>>>
>>> In the case of downcast t1 (being a base class of T) wouldn't be=20
>> convertible (implictly) to any of TR. The implementation do the same thi=
ngs.
>>
>
> Thanks. I am not well-versed with INVOKE, it would be helpful if it said=
=20
> somewhere that the conversion must be
> implicit. Specifying it in terms of static_cast suggests otherwise, so=20
> perhaps that could be said directly
> in the wording?
>

To be clear. That was my intent when I was making this wording and that is=
=20
how my implementation works.
=20

> For current wording this kind of classes will go trough the (*t).*f path.=
=20
>> In my proposed implementation there will be dis-ambiguity between path=
=20
>> using conversion operator and the path going via operator*, so it will b=
e=20
>> no longer valid. Also I find such weird, because they merge the=20
>> pointer-to-C semantics with a obejct-of-type-C semantics, so in my opini=
on=20
>> there is nothing wrong to make them ambiguous in cases of calling member=
=20
>> function of C.
>>
>>
>>
> Well, I think going through the (*t).*f path makes a lot of sense,=20
> compared to going via the conversion operator
> which makes no sense to me, because it creates a temporary anyway. Having=
=20
> such a nonsense conversion
> be ambiguous with the operator* thus doesn't make much sense to me either=
..=20
> In other words, I have a lot
> of preference for operator* being preferred to conversion functions. I=20
> also happen to think that having this
> conversion support is worth breaking that kind of classes, because as I=
=20
> said, I don't find them weird. The
> standard may not include any such classes, but I have seen such code in=
=20
> the wild.
>

Firstly, consider the following function:
struct weird2
{
  C& operator*();
  operator C&();
};
Is there any reason to prefer operator* over conversion operator? For my=20
point of view there is not.

Secondly, consider the following code:
void free_standing(const C&);

free_standing(weird()); //ups, I forgot to invoke *
free_standing(weird2());
In this case the conversion operator will be invoked instead of operator*,=
=20
so I my personal preference would be to preffer conversions over operator*=
=20
(as will free-standing functions do). That difference in personal taste=20
convince me that should cases should end up with compilation error and=20
ambiguity (no silent changes). Secondly using such classes may ends with=20
some non-trivial problems, as the one I tried to present with free standing=
=20
function example.

--=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_591_11492938.1372979908593
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<br><br>W dniu pi=B1tek, 5 lipca 2013 00:52:31 UTC+2 u=BFytkownik Ville Vou=
tilainen napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr"><br><div><br><br><div class=3D"gmail_quote">On 5 July 2013 01:33,  <s=
pan dir=3D"ltr">&lt;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscate=
d-mailto=3D"D1RtVwYk4c8J">toma...@gmail.com</a>&gt;</span> wrote:<br><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><br><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">
<div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span style=
=3D"font-family:courier new,monospace">Define INVOKE (f, t1, t2, ..., tN) a=
s follows:<br>
&mdash; (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to =
a member function of a class T and t1 is convertible to TR where TR is viab=
le reference type for f.</span><br></blockquote></div></div></div></blockqu=
ote>
<div>In the case of downcast t1 (being a base class of T) wouldn't be conve=
rtible (implictly) to any of TR. The implementation do the same things.<br>=
</div></blockquote><div><br></div><div>Thanks. I am not well-versed with IN=
VOKE, it would be helpful if it said somewhere that the conversion must be<=
br>
</div><div class=3D"gmail_quote">implicit. Specifying it in terms of static=
_cast suggests otherwise, so perhaps that could be said directly<br>in the =
wording?<br></div></div></div></div></blockquote><div><br>To be clear. That=
 was my intent when I was making this wording and that is how my implementa=
tion works.<br>&nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margi=
n: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><di=
v dir=3D"ltr"><div><div class=3D"gmail_quote"><div class=3D"gmail_quote"></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-lef=
t:1px #ccc solid;padding-left:1ex">
<div>For current wording this kind of classes will go trough the (*t).*f pa=
th. In my proposed implementation there will be dis-ambiguity between path =
using conversion operator and the path going via operator*, so it will be n=
o longer valid. Also I find such weird, because they merge the pointer-to-C=
 semantics with a obejct-of-type-C semantics, so in my opinion there is not=
hing wrong to make them ambiguous in cases of calling member function of C.=
<br>
</div><div><div><div><br><br></div></div></div></blockquote><div><br></div>=
<div>Well, I think going through the (*t).*f path makes a lot of sense, com=
pared to going via the conversion operator<br>
which makes no sense to me, because it creates a temporary anyway. Having s=
uch a nonsense conversion<br></div><div>be ambiguous with the operator* thu=
s doesn't make much sense to me either. In other words, I have a lot<br>
</div><div>of preference for operator* being preferred to conversion functi=
ons. I also happen to think that having this<br></div><div>conversion suppo=
rt is worth breaking that kind of classes, because as I said, I don't find =
them weird. The<br>
standard may not include any such classes, but I have seen such code in the=
 wild.<br></div></div></div></div></blockquote><div><br>Firstly, consider t=
he following function:<br><span style=3D"font-family:courier new,monospace"=
>struct weird2<br>{<br>&nbsp; C&amp; operator*();<br>&nbsp; operator C&amp;=
();<br>};</span><br>Is there any reason to prefer operator* over conversion=
 operator? For my point of view there is not.<br><br>Secondly, consider the=
 following code:<br>void free_standing(const C&amp;);<br><br>free_standing(=
weird()); //ups, I forgot to invoke *<br>free_standing(weird2());<br>In thi=
s case the conversion operator will be invoked instead of operator*, so I m=
y personal preference would be to preffer conversions over operator* (as wi=
ll free-standing functions do). That difference in personal taste convince =
me that should cases should end up with compilation error and ambiguity (no=
 silent changes). Secondly using such classes may ends with some non-trivia=
l problems, as the one I tried to present with free standing function examp=
le.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_591_11492938.1372979908593--

.


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 16:21:16 -0700 (PDT)
Raw View
------=_Part_1949_3185841.1372980076272
Content-Type: text/plain; charset=ISO-8859-1



> |     struct weird
> |     {
> |       C& operator*();
> |       operator C();
> |     };
> |     But for this cases the problem wont compile, so now silent behavior
> changes
> |     would be introduced.
> |
> |
> | I don't find such a class weird.
>
> Indeed, it isn't.  It isn't far from a wrapper class that turns an
> integer into an iterator.
>
> -- Gaby
>

Why would you need a conversion to int operator in addition to operator*
that retunrs int and int in such wrapper? I probably miss some use cases.

--

---
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_1949_3185841.1372980076272
Content-Type: text/html; charset=ISO-8859-1

<br><blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">| &nbsp; &nbsp; struct weird
<br>| &nbsp; &nbsp; {
<br>| &nbsp; &nbsp; &nbsp; C&amp; operator*();
<br>| &nbsp; &nbsp; &nbsp; operator C();
<br>| &nbsp; &nbsp; };
<br>| &nbsp; &nbsp; But for this cases the problem wont compile, so now silent behavior changes
<br>| &nbsp; &nbsp; would be introduced.
<br>|
<br>|
<br>| I don't find such a class weird.
<br>
<br>Indeed, it isn't. &nbsp;It isn't far from a wrapper class that turns an
<br>integer into an iterator.
<br>
<br>-- Gaby
<br></blockquote><div><br>Why would you need a conversion to int operator in addition to operator* that retunrs int and int in such wrapper? I probably miss some use cases.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an 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 />
&nbsp;<br />
&nbsp;<br />

------=_Part_1949_3185841.1372980076272--

.


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 16:22:41 -0700 (PDT)
Raw View
------=_Part_4547_20999513.1372980161754
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable



W dniu pi=B1tek, 5 lipca 2013 01:08:22 UTC+2 u=BFytkownik Gabriel Dos Reis=
=20
napisa=B3:
>
> Ville Voutilainen <ville.vo...@gmail.com <javascript:>> writes:=20
>
> [...]=20
>
> |     If the new definition will be accepted then, the behavior of the=20
> INVOKE=20
> |     will change for the classes that defines both operator* returning=
=20
> class C=20
> |     and having conversion operator to C, example:=20
> |     struct weird=20
> |     {=20
> |       C& operator*();=20
> |       operator C();=20
> |     };=20
> |     But for this cases the problem wont compile, so now silent behavior=
=20
> changes=20
> |     would be introduced.=20
> |=20
> |=20
> | I don't find such a class weird.=20
>
> Indeed, it isn't.  It isn't far from a wrapper class that turns an=20
> integer into an iterator.=20
>
> -- Gaby=20
>


Why would you need a conversion to int operator in addition to operator*=20
that returns in int in such wrapper?
=20

--=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_4547_20999513.1372980161754
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<br><br>W dniu pi=B1tek, 5 lipca 2013 01:08:22 UTC+2 u=BFytkownik Gabriel D=
os Reis napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Ville Voutil=
ainen &lt;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=
=3D"t82L4Ze2oHwJ">ville.vo...@gmail.com</a>&gt; writes:
<br>
<br>[...]
<br>
<br>| &nbsp; &nbsp; If the new definition will be accepted then, the behavi=
or of the INVOKE
<br>| &nbsp; &nbsp; will change for the classes that defines both operator*=
 returning class C
<br>| &nbsp; &nbsp; and having conversion operator to C, example:
<br>| &nbsp; &nbsp; struct weird
<br>| &nbsp; &nbsp; {
<br>| &nbsp; &nbsp; &nbsp; C&amp; operator*();
<br>| &nbsp; &nbsp; &nbsp; operator C();
<br>| &nbsp; &nbsp; };
<br>| &nbsp; &nbsp; But for this cases the problem wont compile, so now sil=
ent behavior changes
<br>| &nbsp; &nbsp; would be introduced.
<br>|=20
<br>|=20
<br>| I don't find such a class weird.
<br>
<br>Indeed, it isn't. &nbsp;It isn't far from a wrapper class that turns an
<br>integer into an iterator.
<br>
<br>-- Gaby
<br></blockquote><div><br><div><br>Why
 would you need a conversion to int operator in addition to operator*=20
that returns in int in such wrapper?<br></div>&nbsp;<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_4547_20999513.1372980161754--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 02:43:10 +0300
Raw View
--001a11c2ed4a123bbe04e0b824d9
Content-Type: text/plain; charset=ISO-8859-1

On 5 July 2013 02:18, <tomaszkam@gmail.com> wrote:

> In the case of downcast t1 (being a base class of T) wouldn't be
>>> convertible (implictly) to any of TR. The implementation do the same things.
>>>
>>
>> Thanks. I am not well-versed with INVOKE, it would be helpful if it said
>> somewhere that the conversion must be
>> implicit. Specifying it in terms of static_cast suggests otherwise, so
>> perhaps that could be said directly
>> in the wording?
>>
>
> To be clear. That was my intent when I was making this wording and that is
> how my implementation works.
>

I recommend testing that the implementation actually does that, then, and
changing the wording to say that
it really requires implicit convertibility.


>
> Well, I think going through the (*t).*f path makes a lot of sense,
>> compared to going via the conversion operator
>> which makes no sense to me, because it creates a temporary anyway. Having
>> such a nonsense conversion
>> be ambiguous with the operator* thus doesn't make much sense to me
>> either. In other words, I have a lot
>> of preference for operator* being preferred to conversion functions. I
>> also happen to think that having this
>> conversion support is worth breaking that kind of classes, because as I
>> said, I don't find them weird. The
>> standard may not include any such classes, but I have seen such code in
>> the wild.
>>
>
> Firstly, consider the following function:
> struct weird2
> {
>   C& operator*();
>   operator C&();
> };
> Is there any reason to prefer operator* over conversion operator? For my
> point of view there is not.
>

No, but it does no harm, and gives a sane result. Doing the opposite does
no harm either in this
case, but it does harm in the case of the original "struct weird".
Prefering operator* seems sane
in all cases. Perhaps that's why the current INVOKE does it.



>
> Secondly, consider the following code:
> void free_standing(const C&);
>
> free_standing(weird()); //ups, I forgot to invoke *
> free_standing(weird2());
> In this case the conversion operator will be invoked instead of operator*,
> so I my personal preference would be to preffer conversions over operator*
> (as will free-standing functions do). That difference in personal taste
> convince me that should cases
>

INVOKE doesn't model just free-standing functions. It has to make some
compromises to support the variety of things
it supports, one of those compromises being that it can't model
free-standing functions exactly.

--

---
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/.



--001a11c2ed4a123bbe04e0b824d9
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On 5=
 July 2013 02:18,  <span dir=3D"ltr">&lt;<a href=3D"mailto:tomaszkam@gmail.=
com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote: <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><div class=3D"gmail_quote"><blockquote class=3D"gmail=
_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:=
1ex"></blockquote></div></div></div><div class=3D"im"><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"><div><div class=3D"gmail_quote"><blockquote class=3D"gmail=
_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:=
1ex">
<div>In the case of downcast t1 (being a base class of T) wouldn&#39;t be c=
onvertible (implictly) to any of TR. The implementation do the same things.=
<br></div></blockquote><div><br></div><div>Thanks. I am not well-versed wit=
h INVOKE, it would be helpful if it said somewhere that the conversion must=
 be<br>

</div><div class=3D"gmail_quote">implicit. Specifying it in terms of static=
_cast suggests otherwise, so perhaps that could be said directly<br>in the =
wording?<br></div></div></div></div></blockquote></div><div><br>To be clear=
.. That was my intent when I was making this wording and that is how my impl=
ementation works.<br>
</div></blockquote><div><br></div><div>I recommend testing that the impleme=
ntation actually does that, then, and changing the wording to say that<br><=
/div><div>it really requires implicit convertibility.<br>=A0<br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #cc=
c solid;padding-left:1ex">
<br><div class=3D"im"><blockquote class=3D"gmail_quote" style=3D"margin:0;m=
argin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"l=
tr"><div><div class=3D"gmail_quote"><div>Well, I think going through the (*=
t).*f path makes a lot of sense, compared to going via the conversion opera=
tor<br>

which makes no sense to me, because it creates a temporary anyway. Having s=
uch a nonsense conversion<br></div><div>be ambiguous with the operator* thu=
s doesn&#39;t make much sense to me either. In other words, I have a lot<br=
>

</div><div>of preference for operator* being preferred to conversion functi=
ons. I also happen to think that having this<br></div><div>conversion suppo=
rt is worth breaking that kind of classes, because as I said, I don&#39;t f=
ind them weird. The<br>

standard may not include any such classes, but I have seen such code in the=
 wild.<br></div></div></div></div></blockquote></div><div><br>Firstly, cons=
ider the following function:<br><span style=3D"font-family:courier new,mono=
space">struct weird2<br>
{<br>=A0 C&amp; operator*();<br>=A0 operator C&amp;();<br>};</span><br>Is t=
here any reason to prefer operator* over conversion operator? For my point =
of view there is not.<br></div></blockquote><div><br></div><div>No, but it =
does no harm, and gives a sane result. Doing the opposite does no harm eith=
er in this<br>
case, but it does harm in the case of the original &quot;struct weird&quot;=
.. Prefering operator* seems sane<br></div><div>in all cases. Perhaps that&#=
39;s why the current INVOKE does it.<br><br></div><div>=A0<br></div><blockq=
uote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc =
solid;padding-left:1ex">
<div><br>Secondly, consider the following code:<br>void free_standing(const=
 C&amp;);<br><br>free_standing(weird()); //ups, I forgot to invoke *<br>fre=
e_standing(weird2());<br>In this case the conversion operator will be invok=
ed instead of operator*, so I my personal preference would be to preffer co=
nversions over operator* (as will free-standing functions do). That differe=
nce in personal taste convince me that should cases </div>
</blockquote><div><br></div><div>INVOKE doesn&#39;t model just free-standin=
g functions. It has to make some compromises to support the variety of thin=
gs<br>it supports, one of those compromises being that it can&#39;t model f=
ree-standing functions exactly.<br>
<br></div></div></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--001a11c2ed4a123bbe04e0b824d9--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 02:44:30 +0300
Raw View
--047d7b6da616d73d4004e0b828c4
Content-Type: text/plain; charset=ISO-8859-1

On 5 July 2013 02:22, <tomaszkam@gmail.com> wrote:

>
> Indeed, it isn't.  It isn't far from a wrapper class that turns an
>> integer into an iterator.
>>
>> -- Gaby
>>
>
>
> Why would you need a conversion to int operator in addition to operator*
> that returns in int in such wrapper?
>
>
In order to allow the wrapper type to behave both like an int (in a limited
fashion) and like an iterator.

--

---
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/.



--047d7b6da616d73d4004e0b828c4
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 02:22,  <span dir=3D"ltr">&lt;<a href=3D"mailto:toma=
szkam@gmail.com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote=
:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-le=
ft:1px #ccc solid;padding-left:1ex">
<br><div class=3D"im"><blockquote class=3D"gmail_quote" style=3D"margin:0;m=
argin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">Indeed, it is=
n&#39;t. =A0It isn&#39;t far from a wrapper class that turns an
<br>integer into an iterator.
<br>
<br>-- Gaby
<br></blockquote></div><div><br><div><br>Why
 would you need a conversion to int operator in addition to operator*=20
that returns in int in such wrapper?<br></div><br></div></blockquote><div><=
br></div><div>In order to allow the wrapper type to behave both like an int=
 (in a limited fashion) and like an iterator. <br></div></div><br></div>
</div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--047d7b6da616d73d4004e0b828c4--

.


Author: Gabriel Dos Reis <gdr@axiomatics.org>
Date: Thu, 04 Jul 2013 19:48:31 -0500
Raw View
tomaszkam@gmail.com writes:

|     |     struct weird
|     |     {
|     |       C& operator*();
|     |       operator C();
|     |     };
|     |     But for this cases the problem wont compile, so now silent behavior
|     changes
|     |     would be introduced.
|     |
|     |
|     | I don't find such a class weird.
|
|     Indeed, it isn't.  It isn't far from a wrapper class that turns an
|     integer into an iterator.
|
|     -- Gaby
|
|
| Why would you need a conversion to int operator in addition to operator* that
| retunrs int and int in such wrapper? I probably miss some use cases.

It is a wrapper around integer, shouldn't it have that conversion?

-- Gaby

--

---
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/.



.


Author: tomaszkam@gmail.com
Date: Fri, 5 Jul 2013 01:34:18 -0700 (PDT)
Raw View
------=_Part_4586_765730.1373013258557
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable



W dniu pi=B1tek, 5 lipca 2013 01:43:10 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:
>
>
> I recommend testing that the implementation actually does that, then, and=
=20
> changing the wording to say that
> it really requires implicit convertibility.
> =20
>
It was tested against that case.
=20

>
> No, but it does no harm, and gives a sane result. Doing the opposite does=
=20
> no harm either in this
> case, but it does harm in the case of the original "struct weird".=20
> Prefering operator* seems sane
> in all cases. Perhaps that's why the current INVOKE does it.
>
> I would harm in case of:
struct weird3
{
  C operator*();
  operator C&();
};
=20

> =20
> INVOKE doesn't model just free-standing functions. It has to make some=20
> compromises to support the variety of things
> it supports, one of those compromises being that it can't model=20
> free-standing functions exactly.
>
>
For my perspective it does. I see the mem_fn as converting the member=20
function M (Class::*)(Args...) cv ref to be invokable as free=20
standing-function M (Class cv ref, Args...) (if ref is missing there should=
=20
be & and && versions), exactly the same as it used for doing an overload=20
resolution. In addition it supports  pointers to Class and pointer-like=20
types.

W dniu pi=B1tek, 5 lipca 2013 02:48:31 UTC+2 u=BFytkownik Gabriel Dos Reis=
=20
napisa=B3:
>
> It is a wrapper around integer, shouldn't it have that conversion?=20
>

I don't see a point to have that class to act both as a integer and an=20
iterator. I see it would be pretty useful in case of STL algorithms and=20
container, but they will use only operator* to extract the value, not the=
=20
conversions operator. I don't see a point in using it in the context when=
=20
the simple integer will be enough. Maybe I miss something.

--=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_4586_765730.1373013258557
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<br><br>W dniu pi=B1tek, 5 lipca 2013 01:43:10 UTC+2 u=BFytkownik Ville Vou=
tilainen napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr"><div><div class=3D"gmail_quote"><div><br></div><div>I recommend testi=
ng that the implementation actually does that, then, and changing the wordi=
ng to say that<br></div><div>it really requires implicit convertibility.<br=
>&nbsp;<br></div></div></div></div></blockquote><div>It was tested against =
that case.<br>&nbsp;</div><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"><div><div class=3D"gmail_quote"><div><br></div><div>No, but it=
 does no harm, and gives a sane result. Doing the opposite does no harm eit=
her in this<br>
case, but it does harm in the case of the original "struct weird". Preferin=
g operator* seems sane<br></div><div>in all cases. Perhaps that's why the c=
urrent INVOKE does it.<br><br></div></div></div></div></blockquote><div>I w=
ould harm in case of:<br>struct weird3<br>{<br>&nbsp; C operator*();<br>&nb=
sp; operator C&amp;();<br>};<br>&nbsp;</div><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"><div><div class=3D"gmail_quote"><div>&nbsp;<=
/div><div></div><div>INVOKE doesn't model just free-standing functions. It =
has to make some compromises to support the variety of things<br>it support=
s, one of those compromises being that it can't model free-standing functio=
ns exactly.<br>
<br></div></div></div></div></blockquote><br>For my perspective it does. I =
see the <span style=3D"font-family: courier new,monospace;">mem_fn</span> a=
s converting the member function <span style=3D"font-family: courier new,mo=
nospace;">M (Class::*)(Args...) cv ref</span> to be invokable as free stand=
ing-function <span style=3D"font-family: courier new,monospace;">M (Class c=
v ref, Args...) </span>(if ref is missing there should be <span style=3D"fo=
nt-family: courier new,monospace;">&amp;</span> and <span style=3D"font-fam=
ily: courier new,monospace;">&amp;&amp;</span>
 versions), exactly the same as it used for doing an overload=20
resolution. In addition it supports&nbsp; pointers to Class and pointer-lik=
e types.<br><br>W dniu pi=B1tek, 5 lipca 2013 02:48:31 UTC+2 u=BFytkownik G=
abriel Dos Reis napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">It i=
s a wrapper around integer, shouldn't it have that conversion?
<br></blockquote><div><br>I don't see a point to have that class to act bot=
h as a integer and an iterator. I see it would be pretty useful in case of =
STL algorithms and container, but they will use only operator* to extract t=
he value, not the conversions operator. I don't see a point in using it in =
the context when the simple integer will be enough. Maybe I miss something.=
<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_4586_765730.1373013258557--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 14:24:30 +0300
Raw View
--20cf3074d5c4405b1904e0c1f0bc
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

On 5 July 2013 11:34, <tomaszkam@gmail.com> wrote:

>
>
> W dniu pi=B1tek, 5 lipca 2013 01:43:10 UTC+2 u=BFytkownik Ville Voutilain=
en
> napisa=B3:
>
>>
>> I recommend testing that the implementation actually does that, then, an=
d
>> changing the wording to say that
>> it really requires implicit convertibility.
>>
>>
> It was tested against that case.
>

I didn't find such a test in the proof-of-concept code.


>
>
>>
>> No, but it does no harm, and gives a sane result. Doing the opposite doe=
s
>> no harm either in this
>> case, but it does harm in the case of the original "struct weird".
>> Prefering operator* seems sane
>> in all cases. Perhaps that's why the current INVOKE does it.
>>
>> I would harm in case of:
> struct weird3
> {
>   C operator*();
>   operator C&();
> };
>

Now, this actually _is_ a weird type, since it returns a value from its
operator*. If that value happens
to be a proxy value that does the right thing, that's fine - otherwise it
will shoot the user in the foot
in other areas beyond INVOKE, and it's not INVOKE's job to fix that
problem. I see the reasoning
for making such cases ambiguous, but if they aren't ambiguous currently,
I'd want very strong
reasons to introduce potential breakage to existing code, when we can avoid
it.


>
>
>>
>> INVOKE doesn't model just free-standing functions. It has to make some
>> compromises to support the variety of things
>> it supports, one of those compromises being that it can't model
>> free-standing functions exactly.
>>
>>
> For my perspective it does. I see the mem_fn as converting the member
> function M (Class::*)(Args...) cv ref to be invokable as free
> standing-function M (Class cv ref, Args...) (if ref is missing there
> should be & and && versions), exactly the same as it used for doing an
> overload resolution. In addition it supports  pointers to Class and
> pointer-like types.
>

I may have used imprecise terminology. INVOKE certainly unifies target
types so that their invocations become
similar to free functions. However, that doesn't necessarily mean INVOKE
should behave as if all its targets
were free functions, because they aren't.

My recommendation is still to avoid introducing the ambiguity. Otherwise,
the proposal seems good and desirable,
so I'd recommend putting it forward to LEWG. In other words, nice job so
far!

--=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/.



--20cf3074d5c4405b1904e0c1f0bc
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 11:34,  <span dir=3D"ltr">&lt;<a href=3D"mailto:toma=
szkam@gmail.com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote=
:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-le=
ft:1px #ccc solid;padding-left:1ex">

<br><br>W dniu pi=B1tek, 5 lipca 2013 01:43:10 UTC+2 u=BFytkownik Ville Vou=
tilainen napisa=B3:<div><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">
<div><div class=3D"gmail_quote"><div><br></div><div>I recommend testing tha=
t the implementation actually does that, then, and changing the wording to =
say that<br></div><div>it really requires implicit convertibility.<br>=A0<b=
r>

</div></div></div></div></blockquote></div><div>It was tested against that =
case.<br></div></blockquote><div><br></div><div>I didn&#39;t find such a te=
st in the proof-of-concept code.<br>=A0<br></div><blockquote class=3D"gmail=
_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:=
1ex">

<div>=A0</div><div><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"=
><div><div class=3D"gmail_quote"><div><br></div><div>No, but it does no har=
m, and gives a sane result. Doing the opposite does no harm either in this<=
br>


case, but it does harm in the case of the original &quot;struct weird&quot;=
.. Prefering operator* seems sane<br></div><div>in all cases. Perhaps that&#=
39;s why the current INVOKE does it.<br><br></div></div></div></div></block=
quote>

</div><div>I would harm in case of:<br>struct weird3<br>{<br>=A0 C operator=
*();<br>=A0 operator C&amp;();<br>};<br></div></blockquote><div><br></div><=
div>Now, this actually _is_ a weird type, since it returns a value from its=
 operator*. If that value happens<br>

to be a proxy value that does the right thing, that&#39;s fine - otherwise =
it will shoot the user in the foot<br></div><div>in other areas beyond INVO=
KE, and it&#39;s not INVOKE&#39;s job to fix that problem. I see the reason=
ing<br>

for making such cases ambiguous, but if they aren&#39;t ambiguous currently=
, I&#39;d want very strong<br>reasons to introduce potential breakage to ex=
isting code, when we can avoid it.<br>=A0<br></div><blockquote class=3D"gma=
il_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-lef=
t:1ex">

<div>=A0</div><div><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"=
><div><div class=3D"gmail_quote"><div>=A0</div><div></div><div>INVOKE doesn=
&#39;t model just free-standing functions. It has to make some compromises =
to support the variety of things<br>

it supports, one of those compromises being that it can&#39;t model free-st=
anding functions exactly.<br>
<br></div></div></div></div></blockquote><br></div>For my perspective it do=
es. I see the <span style=3D"font-family:courier new,monospace">mem_fn</spa=
n> as converting the member function <span style=3D"font-family:courier new=
,monospace">M (Class::*)(Args...) cv ref</span> to be invokable as free sta=
nding-function <span style=3D"font-family:courier new,monospace">M (Class c=
v ref, Args...) </span>(if ref is missing there should be <span style=3D"fo=
nt-family:courier new,monospace">&amp;</span> and <span style=3D"font-famil=
y:courier new,monospace">&amp;&amp;</span>
 versions), exactly the same as it used for doing an overload=20
resolution. In addition it supports=A0 pointers to Class and pointer-like t=
ypes.<br></blockquote><div><br></div><div>I may have used imprecise termino=
logy. INVOKE certainly unifies target types so that their invocations becom=
e<br>
similar to free functions. However, that doesn&#39;t necessarily mean INVOK=
E should behave as if all its targets<br>were free functions, because they =
aren&#39;t. <br><br></div><div>My recommendation is still to avoid introduc=
ing the ambiguity. Otherwise, the proposal seems good and desirable,<br>
</div><div>so I&#39;d recommend putting it forward to LEWG. In other words,=
 nice job so far!<br></div></div></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--20cf3074d5c4405b1904e0c1f0bc--

.


Author: Gabriel Dos Reis <gdr@axiomatics.org>
Date: Fri, 05 Jul 2013 06:38:49 -0500
Raw View
tomaszkam@gmail.com writes:

[...]

| W dniu pi=B1tek, 5 lipca 2013 02:48:31 UTC+2 u=BFytkownik Gabriel Dos Rei=
s napisa=B3:
|=20
|     It is a wrapper around integer, shouldn't it have that conversion?
|=20
|=20
| I don't see a point to have that class to act both as a integer and an
| iterator. I see it would be pretty useful in case of STL algorithms and
| container, but they will use only operator* to extract the value, not the
| conversions operator. I don't see a point in using it in the context when=
 the
| simple integer will be enough. Maybe I miss something.

Well, just because one doesn't see the point means it is worth breaking.
It would be devastating if one was to use lack of vision as license to
break stuff.  Even though we can't forsee every development, we usually
try hard.

STL principles do not require that a type not provide additional
operations if it already satisfies a certain category of iterator
requirements. In fact, integers form one of the most abstract
representations of iterators.  The whole notion of iterators as you see
them in STL is based on Peano algebra, and a few additional axioms
concerning computational complexity.=20

-- Gaby

--=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/.



.


Author: Gabriel Dos Reis <gdr@axiomatics.org>
Date: Fri, 05 Jul 2013 06:41:27 -0500
Raw View
Ville Voutilainen <ville.voutilainen@gmail.com> writes:

|     struct weird3
|     {
|     =A0 C operator*();
|     =A0 operator C&();
|     };
|=20
|=20
| Now, this actually _is_ a weird type, since it returns a value from its
| operator*.

even vector<bool>::reference doesn't do this.

-- Gaby

--=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/.



.


Author: tomaszkam@gmail.com
Date: Fri, 5 Jul 2013 05:35:33 -0700 (PDT)
Raw View
------=_Part_4849_27236059.1373027733405
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

To avoid breakage of classes that has both operator* and conversion=20
operator to class reference the wording may be changed in the following way=
:
Viable reference types TR for member pointer p of type M T::* are:
  - T cv&, T cv && for all posible CV-qualifications if M is not function=
=20
type
  - T cv&, T cv&& if M is function type without ref-qualification and with=
=20
CV-qualification cv
  - T cv ref if M is function type with ref-qualification ref and with=20
CV-qualification cv

Define INVOKE (f, t1, t2, ..., tN) as follows:
- (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class=
=20
T and t1 is an object of
   type T or a reference to an object of type T or a reference to an object=
=20
of a type derived from T;
-- (static_cast<TR>(*t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and
  t1 does not fulfill criteria of any of previous point and *t1 is=20
convertible to TR where TR is viable
  reference type for f.
-- (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=20
function of a class T and=20
  t1 does not fulfill criteria of any of previous point and *t1 is=20
convertible to TR where TR is viable
  reference type for f.
-- t1.*f when N =3D=3D 1 and f is a pointer to member data of a class T and=
 t1=20
is an object of type T or a
  reference to an object of type T or a reference to an object of a type=20
derived from T;
-- static_cast<TR>(*t1).*f when N =3D=3D 1 and f is a pointer to member dat=
a of=20
a class T and=20
  t1 does not fulfill criteria and *t1 is convertibleto TR where TR is=20
viable reference type for f.
- static_cast<TR>(t1).*f when N =3D=3D 1 and f is a pointer to member data =
of a=20
class T and=20
  t1 does not fulfill criteria t1 is convertible to TR where TR is viable=
=20
reference type for f.
-- f(t1, t2, ..., tN) in all other cases.
This wording would prefer use of operator* over the conversions operator if=
=20
both exists in the classes, so there will be not functionality change with=
=20
this addition. I am pretty sure that that approach is implementable,  but I=
=20
am not sure if I would like to propose to go that direction (see comments=
=20
bellow).

W dniu pi=B1tek, 5 lipca 2013 13:24:30 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:
>
>
> For my perspective it does. I see the mem_fn as converting the member=20
>> function M (Class::*)(Args...) cv ref to be invokable as free=20
>> standing-function M (Class cv ref, Args...) (if ref is missing there=20
>> should be & and && versions), exactly the same as it used for doing an=
=20
>> overload resolution. In addition it supports  pointers to Class and=20
>> pointer-like types.
>>
>
> I may have used imprecise terminology. INVOKE certainly unifies target=20
> types so that their invocations become
> similar to free functions. However, that doesn't necessarily mean INVOKE=
=20
> should behave as if all its targets
> were free functions, because they aren't.=20
>
> But I would like them, to model this functions as close as possible to th=
e=20
free standing functions, so I would rather see prefenrecen of conversion=20
operator over operator*.  But that is the case of the presonal taste, so I=
=20
think that I would be the best to come out with the solution that will=20
choose some default behavior for such classes (probably the going trought=
=20
operator* as it is not breaking) but allow to change it, but at this moment=
=20
I don't see a clean way to do it.

W dniu pi=B1tek, 5 lipca 2013 13:38:49 UTC+2 u=BFytkownik Gabriel Dos Reis=
=20
napisa=B3:
>
> Well, just because one doesn't see the point means it is worth breaking.=
=20
> It would be devastating if one was to use lack of vision as license to=20
> break stuff.  Even though we can't forsee every development, we usually=
=20
> try hard.=20
>
>
Ok, I got your point. The main problem is that standard does not forsee the=
=20
usage of INVOKE with a types with only conversion operator to class type=20
(like std::reference_wrapper).

>

--=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_4849_27236059.1373027733405
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

To avoid breakage of classes that has both operator* and conversion=20
operator to class reference the wording may be changed in the following=20
way:<br><span style=3D"font-family: courier new,monospace;">Viable referenc=
e types TR for member pointer p of type M T::* are:<br>&nbsp; - T cv&amp;, =
T cv &amp;&amp; for all posible CV-qualifications if M is not function type=
<br>&nbsp; - T cv&amp;, T cv&amp;&amp; if M is function type without ref-qu=
alification and with CV-qualification cv<br>&nbsp; - T cv ref  if M is func=
tion type with ref-qualification ref and with CV-qualification cv<br><br>De=
fine INVOKE (f, t1, t2, ..., tN) as follows:<br>- (t1.*f)(t2, ..., tN) when=
 f is a pointer to a member function of a class T and t1 is an object of<br=
>&nbsp;&nbsp; type T or a reference to an object of type T or a reference t=
o an object of a type derived from T;<br>&mdash; (static_cast&lt;TR&gt;(*t1=
).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and<br>&nbsp; t1 does not fulfill </span><span=
 style=3D"font-family: courier new,monospace;"><span style=3D"font-family: =
courier new,monospace;">criteria of any of </span>previous point and *t1 is=
 convertible to TR where TR is=20
viable<br>&nbsp; reference type for f.<br></span><span style=3D"font-family=
: courier new,monospace;"><span style=3D"font-family: courier new,monospace=
;">&mdash;
 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and <br></span></span><span style=3D"font-fami=
ly: courier new,monospace;"><span style=3D"font-family: courier new,monospa=
ce;"><span style=3D"font-family: courier new,monospace;">&nbsp; t1 does not=
 fulfill </span><span style=3D"font-family: courier new,monospace;"><span s=
tyle=3D"font-family: courier new,monospace;">criteria of any of </span>prev=
ious point and *t1 is convertible to TR where TR is=20
viable<br>&nbsp; reference&nbsp;type for f.<br></span></span>&mdash; t1.*f =
when N =3D=3D 1 and f is a pointer to member data of a class T and t1 is an=
 object of type T or a<br>&nbsp; reference to an object of type T or a refe=
rence to an object of a type derived from T;<br></span><span style=3D"font-=
family: courier new,monospace;"><span style=3D"font-family: courier new,mon=
ospace;"><span style=3D"font-family: courier new,monospace;"></span>&mdash;=
=20
static_cast&lt;TR&gt;(*t1).*f when N =3D=3D 1 and f is a pointer to member=
=20
data of a class T and <br>&nbsp; </span></span><span style=3D"font-family: =
courier new,monospace;"><span style=3D"font-family: courier new,monospace;"=
><span style=3D"font-family: courier new,monospace;">t1 does not fulfill </=
span><span style=3D"font-family: courier new,monospace;"><span style=3D"fon=
t-family: courier new,monospace;">criteria and </span></span>*t1 is convert=
ibleto TR where TR is viable=20
reference type for </span>f.<br></span><span style=3D"font-family: courier =
new,monospace;"><span style=3D"font-family: courier new,monospace;"><span s=
tyle=3D"font-family: courier new,monospace;"><span style=3D"font-family: co=
urier new,monospace;">- static_cast&lt;TR&gt;(t1).*f when N =3D=3D
 1 and f is a pointer to member data of a class T  and <br>&nbsp; </span></=
span></span></span><span style=3D"font-family: courier new,monospace;"><spa=
n style=3D"font-family: courier new,monospace;"><span style=3D"font-family:=
 courier new,monospace;"><span style=3D"font-family: courier new,monospace;=
"><span style=3D"font-family: courier new,monospace;"><span style=3D"font-f=
amily: courier new,monospace;"></span></span><span style=3D"font-family: co=
urier new,monospace;"><span style=3D"font-family: courier new,monospace;"><=
span style=3D"font-family: courier new,monospace;">t1 does not fulfill </sp=
an><span style=3D"font-family: courier new,monospace;"><span style=3D"font-=
family: courier new,monospace;">criteria </span></span></span></span> t1 is=
 convertible
 to TR where TR is viable reference type for f.</span></span></span><br>&md=
ash; f(t1, t2, ..., tN) in all other cases.</span><br>This
 wording would prefer use of operator* over the conversions operator if=20
both exists in the classes, so there will be not functionality change=20
with this addition. I am pretty sure that that approach is=20
implementable,&nbsp; but I am not sure if I would like to propose to go tha=
t direction (see comments bellow).<br><br>W dniu pi=B1tek, 5 lipca 2013 13:=
24:30 UTC+2 u=BFytkownik Ville Voutilainen napisa=B3:<blockquote class=3D"g=
mail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc sol=
id;padding-left: 1ex;"><div dir=3D"ltr"><br><div><div class=3D"gmail_quote"=
><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1=
px #ccc solid;padding-left:1ex">For my perspective it does. I see the <span=
 style=3D"font-family:courier new,monospace">mem_fn</span> as converting th=
e member function <span style=3D"font-family:courier new,monospace">M (Clas=
s::*)(Args...) cv ref</span> to be invokable as free standing-function <spa=
n style=3D"font-family:courier new,monospace">M (Class cv ref, Args...) </s=
pan>(if ref is missing there should be <span style=3D"font-family:courier n=
ew,monospace">&amp;</span> and <span style=3D"font-family:courier new,monos=
pace">&amp;&amp;</span>
 versions), exactly the same as it used for doing an overload=20
resolution. In addition it supports&nbsp; pointers to Class and pointer-lik=
e types.<br></blockquote><div><br></div><div>I may have used imprecise term=
inology. INVOKE certainly unifies target types so that their invocations be=
come<br>
similar to free functions. However, that doesn't necessarily mean INVOKE sh=
ould behave as if all its targets<br>were free functions, because they aren=
't. <br><br></div></div></div></div></blockquote><div class=3D"gmail_quote"=
>But I would like them, to model this functions as close as possible to the=
 free standing functions, so I would rather see prefenrecen of conversion o=
perator over operator*.&nbsp; But that is the case of the presonal taste, s=
o I think that I would be the best to come out with the solution that will =
choose some default behavior for such classes (probably the going trought o=
perator* as it is not breaking) but allow to change it, but at this moment =
I don't see a clean way to do it.<br><br>W dniu pi=B1tek, 5 lipca 2013 13:3=
8:49 UTC+2 u=BFytkownik Gabriel Dos Reis napisa=B3:<blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;">Well, just because one doesn't see the point means it =
is worth breaking.
<br>It would be devastating if one was to use lack of vision as license to
<br>break stuff. &nbsp;Even though we can't forsee every development, we us=
ually
<br>try hard.
<br>
<br></blockquote><br>Ok, I got your point. The main problem is that standar=
d does not forsee the usage of INVOKE with a types with only conversion ope=
rator to class type (like std::reference_wrapper).<br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;">
</blockquote>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_4849_27236059.1373027733405--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 15:40:07 +0300
Raw View
--001a113330d2ae1a2d04e0c2fe2f
Content-Type: text/plain; charset=ISO-8859-1

On 5 July 2013 15:35, <tomaszkam@gmail.com> wrote:


>
>> But I would like them, to model this functions as close as possible to
> the free standing functions, so I would rather see prefenrecen of
> conversion operator over operator*.  But that is the case of the presonal
> taste, so I think that I would be the best to come out with the solution
> that will choose some default behavior for such classes (probably the going
> trought operator* as it is not breaking) but allow to change it, but at
> this moment I don't see a clean way to do it.
>



It's not just a matter of taste. The apparently current preference of
operator* (even if as a result of not considering
conversions functions at all) is the status quo in a released standard.
Breaking those semantics should not
be done lightly, even if some personal preference suggests otherwise.

--

---
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/.



--001a113330d2ae1a2d04e0c2fe2f
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 15:35,  <span dir=3D"ltr">&lt;<a href=3D"mailto:toma=
szkam@gmail.com" target=3D"_blank">tomaszkam@gmail.com</a>&gt;</span> wrote=
:<br><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><br><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">
<div><div class=3D"gmail_quote"><div><br></div></div></div></div></blockquo=
te><div class=3D"gmail_quote">But I would like them, to model this function=
s as close as possible to the free standing functions, so I would rather se=
e prefenrecen of conversion operator over operator*.=A0 But that is the cas=
e of the presonal taste, so I think that I would be the best to come out wi=
th the solution that will choose some default behavior for such classes (pr=
obably the going trought operator* as it is not breaking) but allow to chan=
ge it, but at this moment I don&#39;t see a clean way to do it.<br>
</div></blockquote><div><br><br><br></div><div>It&#39;s not just a matter o=
f taste. The apparently current preference of operator* (even if as a resul=
t of not considering<br>conversions functions at all) is the status quo in =
a released standard. Breaking those semantics should not<br>
be done lightly, even if some personal preference suggests otherwise.<br></=
div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--001a113330d2ae1a2d04e0c2fe2f--

.


Author: tomaszkam@gmail.com
Date: Fri, 5 Jul 2013 06:01:13 -0700 (PDT)
Raw View
------=_Part_2408_33494740.1373029273202
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable



W dniu pi=B1tek, 5 lipca 2013 14:40:07 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:
>
>
> But I would like them, to model this functions as close as possible to th=
e=20
>> free standing functions, so I would rather see prefenrecen of conversion=
=20
>> operator over operator*.  But that is the case of the presonal taste, so=
 I=20
>> think that I would be the best to come out with the solution that will=
=20
>> choose some default behavior for such classes (probably the going trough=
t=20
>> operator* as it is not breaking) but allow to change it, but at this mom=
ent=20
>> I don't see a clean way to do it.
>>
>
> It's not just a matter of taste. The apparently current preference of=20
> operator* (even if as a result of not considering
> conversions functions at all) is the status quo in a released standard.=
=20
> Breaking those semantics should not
> be done lightly, even if some personal preference suggests otherwise.
>
> =20
Yes, you are right, I want to say that this will be matter of test if there=
=20
will be no standard rules (I will be in ambiguity fraction then). The main=
=20
problem that I didn't notice before, I that I am breaking the existing code=
=20
(which I would be rather ok with - just may opinion, for me the must have=
=20
it to not introduce silent behavior changes) without providing any=20
work-around for the situations when the problem occur .
=20

--=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_2408_33494740.1373029273202
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<br><br>W dniu pi=B1tek, 5 lipca 2013 14:40:07 UTC+2 u=BFytkownik Ville Vou=
tilainen napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr"><br>
<div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class=
=3D"gmail_quote">But I would like them, to model this functions as close as=
 possible to the free standing functions, so I would rather see prefenrecen=
 of conversion operator over operator*.&nbsp; But that is the case of the p=
resonal taste, so I think that I would be the best to come out with the sol=
ution that will choose some default behavior for such classes (probably the=
 going trought operator* as it is not breaking) but allow to change it, but=
 at this moment I don't see a clean way to do it.<br>
</div></blockquote><div><br></div><div>It's not just a matter of taste. The=
 apparently current preference of operator* (even if as a result of not con=
sidering<br>conversions functions at all) is the status quo in a released s=
tandard. Breaking those semantics should not<br>
be done lightly, even if some personal preference suggests otherwise.<br></=
div></div><br></div></div></blockquote><div>&nbsp;<br>Yes, you are right, I=
 want to say that this will be matter of test if there will be no standard =
rules (I will be in ambiguity fraction then). The main problem that I didn'=
t notice before, I that I am breaking the existing code (which I would be r=
ather ok with - just may opinion, for me the must have it to not introduce =
silent behavior changes) without providing any work-around for the situatio=
ns when the problem occur .<br></div><div>&nbsp;</div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_2408_33494740.1373029273202--

.


Author: tomaszkam@gmail.com
Date: Thu, 4 Jul 2013 16:03:13 -0700 (PDT)
Raw View
------=_Part_4380_8677070.1372978993126
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable



W dniu pi=B1tek, 5 lipca 2013 00:52:31 UTC+2 u=BFytkownik Ville Voutilainen=
=20
napisa=B3:
>
> On 5 July 2013 01:33, <toma...@gmail.com <javascript:>> wrote:
>
>
>> Define INVOKE (f, t1, t2, ..., tN) as follows:
>>>> -- (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a memb=
er=20
>>>> function of a class T and t1 is convertible to TR where TR is viable=
=20
>>>> reference type for f.
>>>>
>>> In the case of downcast t1 (being a base class of T) wouldn't be=20
>> convertible (implictly) to any of TR. The implementation do the same thi=
ngs.
>>
>
> Thanks. I am not well-versed with INVOKE, it would be helpful if it said=
=20
> somewhere that the conversion must be
> implicit. Specifying it in terms of static_cast suggests otherwise, so=20
> perhaps that could be said directly
> in the wording?
>
> To be clear. That is the intent of may wording and that is how my=20
implementation works. I think the standard uses term is convertible in the=
=20
context of implicit conversions.
=20

> For current wording this kind of classes will go trough the (*t).*f path.=
=20
>> In my proposed implementation there will be dis-ambiguity between path=
=20
>> using conversion operator and the path going via operator*, so it will b=
e=20
>> no longer valid. Also I find such weird, because they merge the=20
>> pointer-to-C semantics with a obejct-of-type-C semantics, so in my opini=
on=20
>> there is nothing wrong to make them ambiguous in cases of calling member=
=20
>> function of C.
>>
>>
> Well, I think going through the (*t).*f path makes a lot of sense,=20
> compared to going via the conversion operator
> which makes no sense to me, because it creates a temporary anyway. Having=
=20
> such a nonsense conversion
> be ambiguous with the operator* thus doesn't make much sense to me either=
..=20
> In other words, I have a lot
> of preference for operator* being preferred to conversion functions. I=20
> also happen to think that having this
> conversion support is worth breaking that kind of classes, because as I=
=20
> said, I don't find them weird. The
> standard may not include any such classes, but I have seen such code in=
=20
> the wild.
>
>
Then what about the class:
struct weird2
{
  C& operator*();
  operator C&();
};=20
Is there any reason to prefer operator* over the conversion to reference=20
operator? For my perspective it isn't. In addition
personally I would prefer to always choose a conversions operator over=20
operator*, because it will be used in case of free
standing functions that takes C (or reference) as argument. This difference=
=20
in the personal tates confirms myself that such
cases should be ambiguous.

--=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_4380_8677070.1372978993126
Content-Type: text/html; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable

<br><br>W dniu pi=B1tek, 5 lipca 2013 00:52:31 UTC+2 u=BFytkownik Ville Vou=
tilainen napisa=B3:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr"><div><div class=3D"gmail_quote">On 5 July 2013 01:33,  <span dir=3D"l=
tr">&lt;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
D1RtVwYk4c8J">toma...@gmail.com</a>&gt;</span> wrote:<br><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><br><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">
<div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span style=
=3D"font-family:courier new,monospace">Define INVOKE (f, t1, t2, ..., tN) a=
s follows:<br>
&mdash; (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to =
a member function of a class T and t1 is convertible to TR where TR is viab=
le reference type for f.</span><br></blockquote></div></div></div></blockqu=
ote>
<div>In the case of downcast t1 (being a base class of T) wouldn't be conve=
rtible (implictly) to any of TR. The implementation do the same things.<br>=
</div></blockquote><div><br></div><div>Thanks. I am not well-versed with IN=
VOKE, it would be helpful if it said somewhere that the conversion must be<=
br>
</div><div class=3D"gmail_quote">implicit. Specifying it in terms of static=
_cast suggests otherwise, so perhaps that could be said directly<br>in the =
wording?<br><br></div></div></div></div></blockquote><div>To be clear. That=
 is the intent of may wording and that is how my implementation works. I th=
ink the standard uses term is convertible in the context of implicit conver=
sions.<br>&nbsp;</div><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"><div><div class=3D"gmail_quote"><div class=3D"gmail_quote"></div><=
blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px=
 #ccc solid;padding-left:1ex">
<div>For current wording this kind of classes will go trough the (*t).*f pa=
th. In my proposed implementation there will be dis-ambiguity between path =
using conversion operator and the path going via operator*, so it will be n=
o longer valid. Also I find such weird, because they merge the pointer-to-C=
 semantics with a obejct-of-type-C semantics, so in my opinion there is not=
hing wrong to make them ambiguous in cases of calling member function of C.=
<br>
</div><div><div><div><br></div></div></div></blockquote><div><br></div><div=
>Well, I think going through the (*t).*f path makes a lot of sense, compare=
d to going via the conversion operator<br>
which makes no sense to me, because it creates a temporary anyway. Having s=
uch a nonsense conversion<br></div><div>be ambiguous with the operator* thu=
s doesn't make much sense to me either. In other words, I have a lot<br>
</div><div>of preference for operator* being preferred to conversion functi=
ons. I also happen to think that having this<br></div><div>conversion suppo=
rt is worth breaking that kind of classes, because as I said, I don't find =
them weird. The<br>
standard may not include any such classes, but I have seen such code in the=
 wild.<br></div></div><br></div></div></blockquote><div><br>Then what about=
 the class:<br><span style=3D"font-family: courier new,monospace;">struct w=
eird2<br>{<br>&nbsp; C&amp; operator*();<br>&nbsp; operator C&amp;();<br>};=
</span> <br>Is there any reason to prefer operator* over the conversion to =
reference operator? For my perspective it isn't. In addition<br>personally =
I would prefer to always choose a conversions operator over operator*, beca=
use it will be used in case of free<br>standing functions that takes C (or =
reference) as argument. This difference in the personal tates confirms myse=
lf that such<br>cases should be ambiguous.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_4380_8677070.1372978993126--

.


Author: Jonathan Wakely <cxx@kayari.org>
Date: Fri, 5 Jul 2013 09:47:13 -0700 (PDT)
Raw View
------=_Part_7004_26154865.1373042833850
Content-Type: text/plain; charset=ISO-8859-1

On Friday, July 5, 2013 1:40:07 PM UTC+1, Ville Voutilainen wrote:
>
> It's not just a matter of taste. The apparently current preference of
> operator* (even if as a result of not considering
> conversions functions at all) is the status quo in a released standard.
> Breaking those semantics should not
> be done lightly, even if some personal preference suggests otherwise.
>
>
Making *any* changes to the INVOKE semantics should not be done lightly,
it's seriously tricky stuff!

I'd like to see some more convincing motivation for this change.
std::reference_wrapper is a good motivating case, but I'm less sure about
boost::reference_wrapper ... do you really need another reference_wrapper
if you have a C++11 implementation?  (I'm aware that the boost one allows
incomplete types.)   Such wrapper types can always be made to work with
INVOKE by providing operator* so the last bullet of INVOKE handles them,
although that's a bit smelly, I admit.

--

---
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_7004_26154865.1373042833850
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Friday, July 5, 2013 1:40:07 PM UTC+1, Ville Voutilainen wrote:<blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gma=
il_quote"><div>It's not just a matter of taste. The apparently current pref=
erence of operator* (even if as a result of not considering<br>conversions =
functions at all) is the status quo in a released standard. Breaking those =
semantics should not<br>
be done lightly, even if some personal preference suggests otherwise.<br></=
div></div><br></div></div></blockquote><div><br>Making *any* changes to the=
 INVOKE semantics should not be done lightly, it's seriously tricky stuff!<=
br><br>I'd like to see some more convincing motivation for this change.&nbs=
p; std::reference_wrapper is a good motivating case, but I'm less sure abou=
t boost::reference_wrapper ... do you really need another reference_wrapper=
 if you have a C++11 implementation?&nbsp; (I'm aware that the boost one al=
lows incomplete types.)&nbsp;&nbsp; Such wrapper types can always be made t=
o work with INVOKE by providing operator* so the last bullet of INVOKE hand=
les them, although that's a bit smelly, I admit.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_7004_26154865.1373042833850--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Fri, 5 Jul 2013 20:43:30 +0300
Raw View
--001a11c2c0eca9a73b04e0c73b85
Content-Type: text/plain; charset=ISO-8859-1

On 5 July 2013 19:47, Jonathan Wakely <cxx@kayari.org> wrote:

> On Friday, July 5, 2013 1:40:07 PM UTC+1, Ville Voutilainen wrote:
>>
>> It's not just a matter of taste. The apparently current preference of
>> operator* (even if as a result of not considering
>> conversions functions at all) is the status quo in a released standard.
>> Breaking those semantics should not
>> be done lightly, even if some personal preference suggests otherwise.
>>
>>
> Making *any* changes to the INVOKE semantics should not be done lightly,
> it's seriously tricky stuff!
>
> I'd like to see some more convincing motivation for this change.
> std::reference_wrapper is a good motivating case, but I'm less sure about
> boost::reference_wrapper ... do you really need another reference_wrapper
> if you have a C++11 implementation?  (I'm aware that the boost one allows
> incomplete types.)   Such wrapper types can always be made to work with
> INVOKE by providing operator* so the last bullet of INVOKE handles them,
> although that's a bit smelly, I admit.
>
>
I would find using a wrapper lambda a less smelly alternative. For people
who'd rather not write such things,
this proposal seems quite useful to me - and I expect that types that would
take advantage of it are probably
not types in the standard library or in boost.

This will likely change certain SFINAE results, but I expect those to be
non-breaking, and ultimately
this would allow people to avoid having to SFINAE that kind of cases.
Overall, this looks like something
the LEWG should probably take a look at.

--

---
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/.



--001a11c2c0eca9a73b04e0c73b85
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On 5 July 2013 19:47, Jonathan Wakely <span dir=3D"ltr">&lt;<a href=
=3D"mailto:cxx@kayari.org" target=3D"_blank">cxx@kayari.org</a>&gt;</span> =
wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div class=3D"im">On Friday, July 5, 2013 1:=
40:07 PM UTC+1, Ville Voutilainen wrote:<blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:=
1ex">
<div dir=3D"ltr"><div><div class=3D"gmail_quote"><div>It&#39;s not just a m=
atter of taste. The apparently current preference of operator* (even if as =
a result of not considering<br>conversions functions at all) is the status =
quo in a released standard. Breaking those semantics should not<br>

be done lightly, even if some personal preference suggests otherwise.<br></=
div></div><br></div></div></blockquote></div><div><br>Making *any* changes =
to the INVOKE semantics should not be done lightly, it&#39;s seriously tric=
ky stuff!<br>
<br>I&#39;d like to see some more convincing motivation for this change.=A0=
 std::reference_wrapper is a good motivating case, but I&#39;m less sure ab=
out boost::reference_wrapper ... do you really need another reference_wrapp=
er if you have a C++11 implementation?=A0 (I&#39;m aware that the boost one=
 allows incomplete types.)=A0=A0 Such wrapper types can always be made to w=
ork with INVOKE by providing operator* so the last bullet of INVOKE handles=
 them, although that&#39;s a bit smelly, I admit.<br>
</div><div class=3D"HOEnZb"><div class=3D"h5">



<br></div></div></blockquote><div><br></div><div>I would find using a wrapp=
er lambda a less smelly alternative. For people who&#39;d rather not write =
such things,<br>this proposal seems quite useful to me - and I expect that =
types that would take advantage of it are probably<br>
not types in the standard library or in boost.<br><br></div><div>This will =
likely change certain SFINAE results, but I expect those to be non-breaking=
, and ultimately<br></div><div>this would allow people to avoid having to S=
FINAE that kind of cases. Overall, this looks like something<br>
the LEWG should probably take a look at. <br></div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

--001a11c2c0eca9a73b04e0c73b85--

.


Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@gmail.com>
Date: Fri, 5 Jul 2013 20:29:37 +0200
Raw View
2013/7/5 Jonathan Wakely <cxx@kayari.org>:
> I'd like to see some more convincing motivation for this change.
> std::reference_wrapper is a good motivating case, but I'm less sure about
> boost::reference_wrapper ... do you really need another reference_wrapper if
> you have a C++11 implementation?  (I'm aware that the boost one allows
> incomplete types.)

Btw.: Peter Dimov recently asked on the library reflector whether
std::reference_wrapper shouldn't give up the special member type
protocol to also allow for incomplete types.

- Daniel

--

---
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/.



.


Author: tomaszkam@gmail.com
Date: Fri, 5 Jul 2013 13:47:40 -0700 (PDT)
Raw View
------=_Part_311_29971779.1373057260252
Content-Type: multipart/alternative;
 boundary="----=_Part_312_16557491.1373057260252"

------=_Part_312_16557491.1373057260252
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

I have manage to do proof-of-concept implementation of invoke function=20
compatible with the changed wording. I think it is pretty well self=20
documenting, but should be red in button-up manner (from main).

The current version of the wording.
Viable reference types TR for member pointer p of type M T::* are:
  - T cv&, T cv && for all posible CV-qualifications if M is not function=
=20
type
  - T cv&, T cv&& if M is function type without ref-qualification and with=
=20
CV-qualification cv
  - T cv ref if M is function type with ref-qualification ref and with=20
CV-qualification cv

Define INVOKE (f, t1, t2, ..., tN) as follows:
- (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class=
=20
T and t1 is an object of
   type T or a reference to an object of type T or a reference to an object=
=20
of a type derived from T;
=97 (static_cast<TR>(*t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and
  t1 does not fulfill criteria of any of previous point and *t1 is=20
implicitly convertible to TR where
  TR is viable reference type for f.
=97 (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and=20
  t1 does not fulfill criteria of any of previous point and t1 is implicitl=
yconvertible to TR where=20
  TR is viable reference type for f.
=97 t1.*f when N =3D=3D 1 and f is a pointer to member data of a class T an=
d t1=20
is an object of type T or a
  reference to an object of type T or a reference to an object of a type=20
derived from T;
=97 static_cast<TR>(*t1).*f when N =3D=3D 1 and f is a pointer to member da=
ta of=20
a class T and=20
  t1 does not fulfill criteria and *t1 is implicitly convertible to TR=20
where TR is viable reference type
  for f.
- static_cast<TR>(t1).*f when N =3D=3D 1 and f is a pointer to member data =
of a=20
class T and=20
  t1 does not fulfill criteria t1 is implicitly convertible to TR where TR=
=20
is viable
  reference type for f.
=97 f(t1, t2, ..., tN) in all other cases.
I would appreciate any suggestions for the wording improvements.

2013/7/5 Jonathan Wakely <c...@kayari.org <javascript:>>:=20
> > I'd like to see some more convincing motivation for this change.=20
> > std::reference_wrapper is a good motivating case, but I'm less sure=20
> about=20
> > boost::reference_wrapper ... do you really need another=20
> reference_wrapper if=20
> > you have a C++11 implementation?  (I'm aware that the boost one allows=
=20
> > incomplete types.)=20
>
>  The proposed implementation does handle any wrapper with conversion=20
appropriate conversion operator, so it would support any user defined=20
wrapper class. I do not think that std::reference_wrapper covers all=20
possible usages of such wrappers, but I this point nothing come to may hat,=
=20
except this int wrapped into iterator (but int does not have member=20
methods). Any suggestions?
=20
=20

--=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_312_16557491.1373057260252
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

I have manage to do proof-of-concept implementation of invoke function comp=
atible with the changed wording. I think it is pretty well self documenting=
, but should be red in button-up manner (from main).<br><br>The current ver=
sion of the wording.<br><span style=3D"font-family: courier new,monospace;"=
><div class=3D"GGYB0KICMDB">Viable reference types TR for member pointer p =
of type M T::* are:<br></div>&nbsp; - T cv&amp;, T cv &amp;&amp; for all po=
sible CV-qualifications if M is not function type<div class=3D"GGYB0KICMDB"=
>&nbsp; - T cv&amp;, T cv&amp;&amp; if M is function type without ref-quali=
fication and with CV-qualification cv<br></div><div class=3D"GGYB0KICMDB">&=
nbsp; - T cv ref  if M is function type with ref-qualification ref and with=
 CV-qualification cv<br><br></div><div class=3D"GGYB0KICMDB">Define INVOKE =
(f, t1, t2, ..., tN) as follows:<br></div>- (t1.*f)(t2, ..., tN) when f is =
a pointer to a member function of a class T and t1 is an object of<br>&nbsp=
;&nbsp; type T or a reference to an object of type T or a reference to an o=
bject of a type derived from T;<br>=97 (static_cast&lt;TR&gt;(*t1).*f)(t2, =
...., tN) when f is a pointer to a=20
member function of a class T and<br>&nbsp; t1 does not fulfill </span><span=
 style=3D"font-family: courier new,monospace;"><span style=3D"font-family:c=
ourier new,monospace">criteria of any of </span>previous point and *t1 is i=
mplicitly convertible to TR where<br>&nbsp; TR is=20
viable reference type for f.<br></span><div class=3D"GGYB0KICMDB"><span sty=
le=3D"font-family:courier new,monospace"><span style=3D"font-family:courier=
 new,monospace">=97
 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and <br></span></span></div><span style=3D"fon=
t-family: courier new,monospace;"><span style=3D"font-family:courier new,mo=
nospace"><span style=3D"font-family:courier new,monospace">&nbsp; t1 does n=
ot fulfill </span><span style=3D"font-family:courier new,monospace"><span s=
tyle=3D"font-family:courier new,monospace">criteria of any of </span>previo=
us point and t1 </span></span></span><span style=3D"font-family: courier ne=
w,monospace;"><span style=3D"font-family:courier new,monospace"><span style=
=3D"font-family:courier new,monospace">is</span></span></span><span style=
=3D"font-family: courier new,monospace;"><span style=3D"font-family:courier=
 new,monospace"><span style=3D"font-family:courier new,monospace"><span sty=
le=3D"font-family: courier new,monospace;"><span style=3D"font-family:couri=
er new,monospace"><span style=3D"font-family:courier new,monospace"><span s=
tyle=3D"font-family: courier new,monospace;"> implicitly</span></span></spa=
n></span> convertible to TR where <br>&nbsp; TR is=20
viable reference&nbsp;type for f.<br></span></span>=97 t1.*f when N =3D=3D =
1 and f is a pointer to member data of a class T and t1 is an object of typ=
e T or a<br>&nbsp; reference to an object of type T or a reference to an ob=
ject of a type derived from T;<br></span><span style=3D"font-family: courie=
r new,monospace;"><span style=3D"font-family:courier new,monospace"><span s=
tyle=3D"font-family:courier new,monospace"></span>=97=20
static_cast&lt;TR&gt;(*t1).*f when N =3D=3D 1 and f is a pointer to member=
=20
data of a class T and <br>&nbsp; </span></span><span style=3D"font-family: =
courier new,monospace;"><span style=3D"font-family:courier new,monospace"><=
span style=3D"font-family:courier new,monospace">t1 does not fulfill </span=
><span style=3D"font-family:courier new,monospace"><span style=3D"font-fami=
ly:courier new,monospace">criteria and </span></span>*t1 is </span></span><=
span style=3D"font-family: courier new,monospace;"><span style=3D"font-fami=
ly:courier new,monospace"><span style=3D"font-family: courier new,monospace=
;"><span style=3D"font-family:courier new,monospace"><span style=3D"font-fa=
mily:courier new,monospace"><span style=3D"font-family: courier new,monospa=
ce;">implicitly</span></span></span></span> convertible to TR where TR is v=
iable=20
reference type<br>&nbsp; for </span>f.<br></span><span style=3D"font-family=
: courier new,monospace;"><span style=3D"font-family:courier new,monospace"=
><span style=3D"font-family:courier new,monospace"><span style=3D"font-fami=
ly:courier new,monospace">- static_cast&lt;TR&gt;(t1).*f when N =3D=3D
 1 and f is a pointer to member data of a class T  and <br>&nbsp; </span></=
span></span></span><span style=3D"font-family: courier new,monospace;"><spa=
n style=3D"font-family:courier new,monospace"><span style=3D"font-family:co=
urier new,monospace"><span style=3D"font-family:courier new,monospace"><spa=
n style=3D"font-family:courier new,monospace"><span style=3D"font-family:co=
urier new,monospace"></span></span><span style=3D"font-family:courier new,m=
onospace"><span style=3D"font-family:courier new,monospace"><span style=3D"=
font-family:courier new,monospace">t1 does not fulfill </span><span style=
=3D"font-family:courier new,monospace"><span style=3D"font-family:courier n=
ew,monospace">criteria </span></span></span></span> t1 is </span></span></s=
pan></span><span style=3D"font-family: courier new,monospace;"><span style=
=3D"font-family:courier new,monospace"><span style=3D"font-family:courier n=
ew,monospace"><span style=3D"font-family:courier new,monospace"><span style=
=3D"font-family: courier new,monospace;"><span style=3D"font-family:courier=
 new,monospace"><span style=3D"font-family:courier new,monospace"><span sty=
le=3D"font-family: courier new,monospace;">implicitly</span></span></span><=
/span> convertible
 to TR where TR is viable<br>&nbsp; reference type for f.</span></span></sp=
an><div class=3D"GGYB0KICMDB">=97 f(t1, t2, ..., tN) in all other cases.</d=
iv></span>I would appreciate any suggestions for the wording improvements.<=
br><br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">2013/7/5 Jonathan Wakel=
y &lt;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"el=
VswZyxq7QJ">c...@kayari.org</a>&gt;:
<br>&gt; I'd like to see some more convincing motivation for this change.
<br>&gt; std::reference_wrapper is a good motivating case, but I'm less sur=
e about
<br>&gt; boost::reference_wrapper ... do you really need another reference_=
wrapper if
<br>&gt; you have a C++11 implementation? &nbsp;(I'm aware that the boost o=
ne allows
<br>&gt; incomplete types.)
<br>
<br></blockquote><div>&nbsp;The proposed implementation does handle any wra=
pper with conversion appropriate conversion operator, so it would support a=
ny user defined wrapper class. I do not think that std::reference_wrapper c=
overs all possible usages of such wrappers, but I this point nothing come t=
o may hat, except this int wrapped into iterator (but int does not have mem=
ber methods). Any suggestions?<br></div><div>&nbsp;</div><div>&nbsp;</div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_312_16557491.1373057260252--
------=_Part_311_29971779.1373057260252
Content-Type: text/x-c++src; charset=US-ASCII;
 name=invoke_without_breaking.cpp
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=invoke_without_breaking.cpp
X-Attachment-Id: f6ff30d1-7fdc-43e0-9c54-8a0845113596
Content-ID: <f6ff30d1-7fdc-43e0-9c54-8a0845113596>

#include <memory>
#include <type_traits>
#include <tuple>

//Viable references getter
template<typename Class, typename Member>
struct viable_references_impl
{
  typedef std::tuple<
    Class&, Class&&,
    Class const&, Class const&&,
    Class volatile&, Class volatile&&,
    Class const volatile&, Class const volatile&&
  > type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...)>
{
  typedef std::tuple<Class&, Class&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const>
{
  typedef std::tuple<Class const&, Class const&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile>
{
  typedef std::tuple<Class volatile&, Class volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile>
{
  typedef std::tuple<Class const volatile&, Class const volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) &>
{
  typedef std::tuple<Class&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const&>
{
  typedef std::tuple<Class const&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile&>
{
  typedef std::tuple<Class volatile&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile&>
{
  typedef std::tuple<Class const volatile&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) &&>
{
  typedef std::tuple<Class&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const&&>
{
  typedef std::tuple<Class const&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile&&>
{
  typedef std::tuple<Class volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile&&>
{
  typedef std::tuple<Class const volatile&&> type;
};

template<typename T>
struct viable_references
{
  typedef std::tuple<> type;
};

template<typename Class, typename Member>
struct viable_references<Member Class::*>
{
  typedef typename viable_references_impl<Class, Member>::type type;
};

template<typename T>
using viable_references_t = typename viable_references<T>::type;

//MPL or
constexpr bool predicate_or()
{
  return false;
};

template<typename Pred, typename... Preds>
constexpr bool predicate_or(Pred&& pred, Preds&&... preds)
{
  return pred || predicate_or(std::forward<Preds>(preds)...);
};

//Predicate checking
template<typename Object, typename Type>
struct is_wrapper_compatible_with_member_pointer_impl : public std::false_type
{};

template<typename Object, typename... ViableRefs>
struct is_wrapper_compatible_with_member_pointer_impl<Object, std::tuple<ViableRefs...>>
  : std::integral_constant<bool, predicate_or(std::is_convertible<Object, ViableRefs>{}...)>
{};

template<typename Object, typename Pointer>
struct is_wrapper_compatible_with_member_pointer
  : is_wrapper_compatible_with_member_pointer_impl<Object, viable_references_t<Pointer>>
{};

template<typename Object, typename Pointer>
constexpr bool is_pointer_compatible_with_member_pointer_impl(typename std::decay<decltype(*std::declval<Object>())>::type*)
{
  return is_wrapper_compatible_with_member_pointer<decltype(*std::declval<Object>()), Pointer>::value;
}

template<typename Object, typename Pointer>
constexpr bool is_pointer_compatible_with_member_pointer_impl(...)
{
  return false;
}

template<typename Object, typename Pointer>
struct is_pointer_compatible_with_member_pointer
 : public std::integral_constant<bool, is_pointer_compatible_with_member_pointer_impl<Object, Pointer>(0)>
{};

//Class target
template<typename T>
struct target_type
{
  typedef void type;
};

template<typename Class, typename Member>
struct target_type<Member Class::*>
{
  typedef Class type;
};

//Is reference to pointer target or derived
template<typename Object, typename Pointer>
struct is_target_reference :
  public std::integral_constant<
           bool,
           std::is_reference<Object>::value &&
           std::is_base_of<
             typename target_type<Pointer>::type,
             typename std::decay<Object>::type
           >::value
         >
{};

//To viable ref functor
template<typename... Ts>
struct to_viable_ref_functor_combiner
{};

template<typename T>
struct to_viable_ref_functor_combiner<T>
{
  T operator()(T t) const
  {
    return std::forward<T>(t);
  }
};

template<typename T1, typename T2, typename... Ts>
struct to_viable_ref_functor_combiner<T1, T2, Ts...>
  : to_viable_ref_functor_combiner<T1>,
    to_viable_ref_functor_combiner<T2, Ts...>
{
  using to_viable_ref_functor_combiner<T1>::operator();
  using to_viable_ref_functor_combiner<T2, Ts...>::operator();
};

template<typename T>
struct to_viable_ref_impl
{};

template<typename... Ts>
struct to_viable_ref_impl<std::tuple<Ts...>>
  : to_viable_ref_functor_combiner<Ts...>
{};

template<typename Pointer>
struct to_viable_ref
 : to_viable_ref_impl<viable_references_t<typename std::decay<Pointer>::type>>
{};


template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((object.*functor)(std::forward<Args>(args)...))
      >::type
{
  return (object.*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        !is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_wrapper_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}


template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(object.*functor)
      >::type
{
  return object.*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        !is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_wrapper_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor;
}

template<typename Functor, typename... Args>
inline auto invoke(Functor&& functor, Args&&... args)
  ->  typename std::enable_if<
        !std::is_member_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
      >::type
{
  return std::forward<Functor>(functor)(std::forward<Args>(args)...);
}

struct Base {};

struct Class : Base
{
  void normal() {}
  void reference()& {}
  int member;
};

struct Derived : Class {};

struct Conversion
{
  Class clazz;

  operator Class&() { return clazz; }
};

struct Pointer
{
  Class clazz;

  Class& operator*() { return clazz; }
};

struct Mixed
{
  Class clazz;

  Class& operator*() { return clazz; }
  operator Class() { throw std::logic_error("Conversion operator invoked for type with operator*"); }
};

static_assert(!is_target_reference<Base&, int Class::*>::value, "checking Base");
static_assert(!is_target_reference<Pointer&, int Class::*>::value, "checking Pointer");
static_assert(!is_target_reference<Mixed&, int Class::*>::value, "checking Mixed");

static_assert(is_target_reference<Class&, int Class::*>::value, "checking Class&");
static_assert(is_target_reference<Class const&, int Class::*>::value, "checking Class const&");
static_assert(is_target_reference<Class&&, int Class::*>::value, "checking Class&");
static_assert(is_target_reference<Class const&&, int Class::*>::value, "checking Class const&&");

static_assert(is_target_reference<Derived&, int Derived::*>::value, "checking Derived&");
static_assert(is_target_reference<Derived const&, int Derived::*>::value, "checking Derived const&");
static_assert(is_target_reference<Derived&&, int Derived::*>::value, "checking Derived&");
static_assert(is_target_reference<Derived const&&, int Derived::*>::value, "checking Derived const&&");

Base base;
Class clazz;
Derived derived;
Class* rawPointer;
Pointer smartPointer;
Conversion conversion;
Mixed mixed;

static_assert(!is_pointer_compatible_with_member_pointer<decltype(base), int Class::*>::value, "checking Base");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(clazz), int Class::*>::value, "checking Class");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(derived), int Class::*>::value, "checking Derived");
static_assert(is_pointer_compatible_with_member_pointer<decltype(rawPointer), int Class::*>::value, "checking RawPointer");
static_assert(is_pointer_compatible_with_member_pointer<decltype(smartPointer), int Class::*>::value, "checking SmartPointer");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(conversion), int Class::*>::value, "checking Conversion");
static_assert(is_pointer_compatible_with_member_pointer<decltype(mixed), int Class::*>::value, "checking Mixed");

static_assert(!is_wrapper_compatible_with_member_pointer<decltype(base), int Class::*>::value, "checking Base");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(clazz), int Class::*>::value, "checking Class");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(derived), int Class::*>::value, "checking Derived");
static_assert(!is_wrapper_compatible_with_member_pointer<decltype(rawPointer), int Class::*>::value, "checking RawPointer");
static_assert(!is_wrapper_compatible_with_member_pointer<decltype(smartPointer), int Class::*>::value, "checking SmartPointer");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(conversion), int Class::*>::value, "checking Conversion");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(mixed), int Class::*>::value, "checking Mixed");


int main()
{
  invoke(&Class::normal, Class{});
  //invoke(&Class::normal, base);
  invoke(&Class::normal, clazz);
  invoke(&Class::normal, derived);
  invoke(&Class::normal, rawPointer);
  invoke(&Class::normal, smartPointer);
  invoke(&Class::normal, conversion);
  invoke(&Class::normal, mixed);

  /* Wont work on gcc 4.8.1 and clang 3.2 because of bug with in implementation
     of is_member_function_pointer for ref qualified methods.
     See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57388
          http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57825
  //invoke(&Class::reference, Class{});
  //invoke(&Class::reference, base);
  invoke(&Class::reference, clazz);
  invoke(&Class::reference, derived);
  invoke(&Class::reference, rawPointer);
  invoke(&Class::reference, smartPointer);
  invoke(&Class::reference, conversion);
  invoke(&Class::reference, mixed);*/

  invoke(&Class::member, Class{});
  //invoke(&Class::member, base);
  invoke(&Class::member, clazz);
  invoke(&Class::member, derived);
  invoke(&Class::member, rawPointer);
  invoke(&Class::member, smartPointer);
  invoke(&Class::member, conversion);
  invoke(&Class::member, mixed);

  invoke([](int) {}, 1);
}

------=_Part_311_29971779.1373057260252--

.


Author: tomaszkam@gmail.com
Date: Fri, 5 Jul 2013 14:18:52 -0700 (PDT)
Raw View
------=_Part_428_16155270.1373059132392
Content-Type: multipart/alternative;
 boundary="----=_Part_429_30326717.1373059132392"

------=_Part_429_30326717.1373059132392
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

I have manage to do proof-of-concept implementation of invoke function=20
compatible with the changed wording. I think it is pretty well self=20
documenting, but should be red in button-up manner (from main).

The corrected version of the wording.
Viable reference types TR for member pointer p of type M T::* are:
  - T cv&, T cv && for all posible CV-qualifications if M is not function=
=20
type
  - T cv&, T cv&& if M is function type without ref-qualification and with=
=20
CV-qualification cv
  - T cv ref if M is function type with ref-qualification ref and with=20
CV-qualification cv

Define INVOKE (f, t1, t2, ..., tN) as follows:
- (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class=
=20
T and t1 is an object of
   type T or a reference to an object of type T or a reference to an object=
=20
of a type derived from T;
=97 (static_cast<TR>(*t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and
  t1 does not fulfill criteria of any of previous point and *t1 is=20
implicitly convertible to TR where
  TR is viable reference type for f.
=97 (static_cast<TR>(t1).*f)(t2, ..., tN) when f is a pointer to a member=
=20
function of a class T and=20
  t1 does not fulfill criteria of any of previous point and t1 is implicitl=
yconvertible to TR where=20
  TR is viable reference type for f.
=97 t1.*f when N =3D=3D 1 and f is a pointer to member data of a class T an=
d t1=20
is an object of type T or a
  reference to an object of type T or a reference to an object of a type=20
derived from T;
=97 static_cast<TR>(*t1).*f when N =3D=3D 1 and f is a pointer to member da=
ta of=20
a class T and=20
  t1 does not fulfill criteria of any of previous point and *t1 is=20
implicitly convertible to TR where
  TR is viable reference type for f.
- static_cast<TR>(t1).*f when N =3D=3D 1 and f is a pointer to member data =
of a=20
class T and=20
  t1 does not fulfill criteria of any of previous point and t1 is implicitl=
yconvertible to TR where
  TR is viable reference type for f.
=97 f(t1, t2, ..., tN) in all other cases.
I would appreciate any suggestions for the wording improvements.


2013/7/5 Jonathan Wakely <c...@kayari.org>:=20
> > I'd like to see some more convincing motivation for this change.=20
> > std::reference_wrapper is a good motivating case, but I'm less sure=20
> about=20
> > boost::reference_wrapper ... do you really need another=20
> reference_wrapper if=20
> > you have a C++11 implementation?  (I'm aware that the boost one allows=
=20
> > incomplete types.)=20
>
>  The proposed wording does support any wrapper with appropriate conversio=
n=20
operator, so it would support any user defined wrapper class. From the=20
other side, I  do not think that std::reference_wrapper covers all possible=
=20
usages of such wrappers, but at this point nothing come to my mind, except=
=20
the int wrapped into iterator (but int does not have member methods). Any=
=20
suggestions?
=20

--=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_429_30326717.1373059132392
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

I have manage to do proof-of-concept implementation of invoke function=20
compatible with the changed wording. I think it is pretty well self=20
documenting, but should be red in button-up manner (from main).<br><br>The =
corrected version of the wording.<br><span style=3D"font-family: courier ne=
w,monospace;"><div class=3D"GGYB0KICMDB"><div>Viable reference types TR for=
 member pointer p of type M T::* are:<br></div>&nbsp; - T cv&amp;, T cv &am=
p;&amp; for all posible CV-qualifications if M is not function type<div>&nb=
sp; - T cv&amp;, T cv&amp;&amp; if M is function type without ref-qualifica=
tion and with CV-qualification cv<br></div><div>&nbsp; - T cv ref  if M is =
function type with ref-qualification ref and with CV-qualification cv<br><b=
r></div><div>Define INVOKE (f, t1, t2, ..., tN) as follows:<br></div>- (t1.=
*f)(t2, ..., tN) when f is a pointer to a member function of a class T and =
t1 is an object of<br>&nbsp;&nbsp; type T or a reference to an object of ty=
pe T or a reference to an object of a type derived from T;<br>=97 (static_c=
ast&lt;TR&gt;(*t1).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and<br></div>&nbsp; t1 does not fulfill </span=
><span style=3D"font-family: courier new,monospace;"><span style=3D"font-fa=
mily:courier new,monospace">criteria of any of </span>previous point and *t=
1 is implicitly convertible to TR where<div class=3D"GGYB0KICMDB">&nbsp; TR=
 is=20
viable reference type for f.<br></div></span><div class=3D"GGYB0KICMDB"><di=
v><span style=3D"font-family:courier new,monospace"><span style=3D"font-fam=
ily:courier new,monospace">=97
 (static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN) when f is a pointer to a=20
member function of a class T and <br></span></span></div></div><span style=
=3D"font-family: courier new,monospace;"><span style=3D"font-family:courier=
 new,monospace"><span style=3D"font-family:courier new,monospace">&nbsp; t1=
 does not fulfill </span><span style=3D"font-family:courier new,monospace">=
<span style=3D"font-family:courier new,monospace">criteria of any of </span=
>previous point and t1 </span></span></span><span style=3D"font-family: cou=
rier new,monospace;"><span style=3D"font-family:courier new,monospace"><spa=
n style=3D"font-family:courier new,monospace">is</span></span></span><span =
style=3D"font-family: courier new,monospace;"><span style=3D"font-family:co=
urier new,monospace"><span style=3D"font-family:courier new,monospace"><spa=
n style=3D"font-family:courier new,monospace"><span style=3D"font-family:co=
urier new,monospace"><span style=3D"font-family:courier new,monospace"><spa=
n style=3D"font-family:courier new,monospace"> implicitly</span></span></sp=
an></span> convertible to TR where <br><div class=3D"GGYB0KICMDB">&nbsp; TR=
 is=20
viable reference&nbsp;type for f.<br></div></span></span><div class=3D"GGYB=
0KICMDB">=97 t1.*f when N =3D=3D 1 and f is a pointer to member data of a c=
lass T and t1 is an object of type T or a<br>&nbsp; reference to an object =
of type T or a reference to an object of a type derived from T;<br></div></=
span><span style=3D"font-family: courier new,monospace;"><span style=3D"fon=
t-family:courier new,monospace"><div class=3D"GGYB0KICMDB"><span style=3D"f=
ont-family:courier new,monospace"></span>=97=20
static_cast&lt;TR&gt;(*t1).*f when N =3D=3D 1 and f is a pointer to member=
=20
data of a class T and <br></div>&nbsp; </span></span><span style=3D"font-fa=
mily: courier new,monospace;"><span style=3D"font-family:courier new,monosp=
ace"><span style=3D"font-family:courier new,monospace">t1 does not fulfill =
</span><span style=3D"font-family:courier new,monospace"><span style=3D"fon=
t-family:courier new,monospace">criteria </span></span></span></span><span =
style=3D"font-family: courier new,monospace;"><span style=3D"font-family:co=
urier new,monospace"><span style=3D"font-family:courier new,monospace"><spa=
n style=3D"font-family:courier new,monospace"><span style=3D"font-family: c=
ourier new,monospace;"><span style=3D"font-family:courier new,monospace"><s=
pan style=3D"font-family:courier new,monospace"><span style=3D"font-family:=
courier new,monospace">of any of </span>previous point </span></span></span=
>and </span></span>*t1 is </span></span><span style=3D"font-family: courier=
 new,monospace;"><span style=3D"font-family:courier new,monospace"><span st=
yle=3D"font-family:courier new,monospace"><span style=3D"font-family:courie=
r new,monospace"><span style=3D"font-family:courier new,monospace"><span st=
yle=3D"font-family:courier new,monospace">implicitly</span></span></span></=
span> convertible to TR where<br>&nbsp; TR is viable=20
reference type for </span>f.<br></span><span style=3D"font-family: courier =
new,monospace;"><span style=3D"font-family:courier new,monospace"><span sty=
le=3D"font-family:courier new,monospace"><span style=3D"font-family:courier=
 new,monospace"><div class=3D"GGYB0KICMDB">- static_cast&lt;TR&gt;(t1).*f w=
hen N =3D=3D
 1 and f is a pointer to member data of a class T  and <br></div>&nbsp; </s=
pan></span></span></span><span style=3D"font-family: courier new,monospace;=
"><span style=3D"font-family:courier new,monospace"><span style=3D"font-fam=
ily:courier new,monospace"><span style=3D"font-family:courier new,monospace=
"><span style=3D"font-family:courier new,monospace"><span style=3D"font-fam=
ily:courier new,monospace"></span></span><span style=3D"font-family:courier=
 new,monospace"><span style=3D"font-family:courier new,monospace"><span sty=
le=3D"font-family:courier new,monospace">t1 does not fulfill </span><span s=
tyle=3D"font-family:courier new,monospace"><span style=3D"font-family:couri=
er new,monospace">criteria </span></span></span></span></span></span></span=
></span><span style=3D"font-family: courier new,monospace;"><span style=3D"=
font-family:courier new,monospace"><span style=3D"font-family:courier new,m=
onospace"><span style=3D"font-family:courier new,monospace"><span style=3D"=
font-family:courier new,monospace"><span style=3D"font-family:courier new,m=
onospace"><span style=3D"font-family:courier new,monospace"><span style=3D"=
font-family:courier new,monospace"><span style=3D"font-family: courier new,=
monospace;"><span style=3D"font-family:courier new,monospace"><span style=
=3D"font-family:courier new,monospace"><span style=3D"font-family:courier n=
ew,monospace">of any of </span>previous point</span></span></span> </span><=
/span></span></span> and t1 is </span></span></span></span><span style=3D"f=
ont-family: courier new,monospace;"><span style=3D"font-family:courier new,=
monospace"><span style=3D"font-family:courier new,monospace"><span style=3D=
"font-family:courier new,monospace"><span style=3D"font-family:courier new,=
monospace"><span style=3D"font-family:courier new,monospace"><span style=3D=
"font-family:courier new,monospace"><span style=3D"font-family:courier new,=
monospace">implicitly</span></span></span></span> convertible
 to TR where<br>&nbsp; TR is viable reference type for f.</span></span></sp=
an><div>=97 f(t1, t2, ..., tN) in all other cases.</div></span>I would appr=
eciate any suggestions for the wording improvements.<div class=3D"GGYB0KICM=
DB"><br><br><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex">2013/7/5 Jonathan Wakel=
y &lt;<a>c...@kayari.org</a>&gt;:
<br>&gt; I'd like to see some more convincing motivation for this change.
<br>&gt; std::reference_wrapper is a good motivating case, but I'm less sur=
e about
<br>&gt; boost::reference_wrapper ... do you really need another reference_=
wrapper if
<br>&gt; you have a C++11 implementation? &nbsp;(I'm aware that the boost o=
ne allows
<br>&gt; incomplete types.)
<br>
<br></blockquote></div><div>&nbsp;The proposed wording does support any
 wrapper with appropriate conversion operator, so it would=20
support any user defined wrapper class. From the other side, I&nbsp; do not=
 think that=20
std::reference_wrapper covers all possible usages of such wrappers, but at
 this point nothing come to my mind, except the int wrapped into=20
iterator (but int does not have member methods). Any suggestions?<br></div>=
<div>&nbsp;</div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_429_30326717.1373059132392--
------=_Part_428_16155270.1373059132392
Content-Type: text/x-c++src; charset=US-ASCII;
 name=invoke_without_breaking.cpp
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=invoke_without_breaking.cpp
X-Attachment-Id: c9a371bd-1639-47d8-adab-7b36fb6953e7
Content-ID: <c9a371bd-1639-47d8-adab-7b36fb6953e7>

#include <memory>
#include <type_traits>
#include <tuple>

//Viable references getter
template<typename Class, typename Member>
struct viable_references_impl
{
  typedef std::tuple<
    Class&, Class&&,
    Class const&, Class const&&,
    Class volatile&, Class volatile&&,
    Class const volatile&, Class const volatile&&
  > type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...)>
{
  typedef std::tuple<Class&, Class&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const>
{
  typedef std::tuple<Class const&, Class const&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile>
{
  typedef std::tuple<Class volatile&, Class volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile>
{
  typedef std::tuple<Class const volatile&, Class const volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) &>
{
  typedef std::tuple<Class&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const&>
{
  typedef std::tuple<Class const&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile&>
{
  typedef std::tuple<Class volatile&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile&>
{
  typedef std::tuple<Class const volatile&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) &&>
{
  typedef std::tuple<Class&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const&&>
{
  typedef std::tuple<Class const&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) volatile&&>
{
  typedef std::tuple<Class volatile&&> type;
};

template<typename Class, typename Ret, typename... Args>
struct viable_references_impl<Class, Ret(Args...) const volatile&&>
{
  typedef std::tuple<Class const volatile&&> type;
};

template<typename T>
struct viable_references
{
  typedef std::tuple<> type;
};

template<typename Class, typename Member>
struct viable_references<Member Class::*>
{
  typedef typename viable_references_impl<Class, Member>::type type;
};

template<typename T>
using viable_references_t = typename viable_references<T>::type;

//MPL or
constexpr bool predicate_or()
{
  return false;
};

template<typename Pred, typename... Preds>
constexpr bool predicate_or(Pred&& pred, Preds&&... preds)
{
  return pred || predicate_or(std::forward<Preds>(preds)...);
};

//Predicate checking
template<typename Object, typename Type>
struct is_wrapper_compatible_with_member_pointer_impl : public std::false_type
{};

template<typename Object, typename... ViableRefs>
struct is_wrapper_compatible_with_member_pointer_impl<Object, std::tuple<ViableRefs...>>
  : std::integral_constant<bool, predicate_or(std::is_convertible<Object, ViableRefs>{}...)>
{};

template<typename Object, typename Pointer>
struct is_wrapper_compatible_with_member_pointer
  : is_wrapper_compatible_with_member_pointer_impl<Object, viable_references_t<Pointer>>
{};

template<typename Object, typename Pointer>
constexpr bool is_pointer_compatible_with_member_pointer_impl(typename std::decay<decltype(*std::declval<Object>())>::type*)
{
  return is_wrapper_compatible_with_member_pointer<decltype(*std::declval<Object>()), Pointer>::value;
}

template<typename Object, typename Pointer>
constexpr bool is_pointer_compatible_with_member_pointer_impl(...)
{
  return false;
}

template<typename Object, typename Pointer>
struct is_pointer_compatible_with_member_pointer
 : public std::integral_constant<bool, is_pointer_compatible_with_member_pointer_impl<Object, Pointer>(0)>
{};

//Class target
template<typename T>
struct target_type
{
  typedef void type;
};

template<typename Class, typename Member>
struct target_type<Member Class::*>
{
  typedef Class type;
};

//Is reference to pointer target or derived
template<typename Object, typename Pointer>
struct is_target_reference :
  public std::integral_constant<
           bool,
           std::is_reference<Object>::value &&
           std::is_base_of<
             typename target_type<Pointer>::type,
             typename std::decay<Object>::type
           >::value
         >
{};

//To viable ref functor
template<typename... Ts>
struct to_viable_ref_functor_combiner
{};

template<typename T>
struct to_viable_ref_functor_combiner<T>
{
  T operator()(T t) const
  {
    return std::forward<T>(t);
  }
};

template<typename T1, typename T2, typename... Ts>
struct to_viable_ref_functor_combiner<T1, T2, Ts...>
  : to_viable_ref_functor_combiner<T1>,
    to_viable_ref_functor_combiner<T2, Ts...>
{
  using to_viable_ref_functor_combiner<T1>::operator();
  using to_viable_ref_functor_combiner<T2, Ts...>::operator();
};

template<typename T>
struct to_viable_ref_impl
{};

template<typename... Ts>
struct to_viable_ref_impl<std::tuple<Ts...>>
  : to_viable_ref_functor_combiner<Ts...>
{};

template<typename Pointer>
struct to_viable_ref
 : to_viable_ref_impl<viable_references_t<typename std::decay<Pointer>::type>>
{};


template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((object.*functor)(std::forward<Args>(args)...))
      >::type
{
  return (object.*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}

template<typename Functor, typename Object, typename... Args>
inline auto invoke(Functor&& functor, Object&& object, Args&&... args)
  ->  typename std::enable_if<
        std::is_member_function_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        !is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_wrapper_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype((to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...))
      >::type
{
  return (to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)(std::forward<Args>(args)...);
}


template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(object.*functor)
      >::type
{
  return object.*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(*std::forward<Object>(object)).*functor;
}

template<typename Functor, typename Object>
inline auto invoke(Functor&& functor, Object&& object)
  ->  typename std::enable_if<
        std::is_member_object_pointer<
          typename std::decay<Functor>::type
        >::value &&
        !is_target_reference<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        !is_pointer_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value &&
        is_wrapper_compatible_with_member_pointer<
          Object&&,
          typename std::decay<Functor>::type
        >::value,
        decltype(to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor)
      >::type
{
  return to_viable_ref<Functor>{}(std::forward<Object>(object)).*functor;
}

template<typename Functor, typename... Args>
inline auto invoke(Functor&& functor, Args&&... args)
  ->  typename std::enable_if<
        !std::is_member_pointer<
          typename std::decay<Functor>::type
        >::value,
        decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
      >::type
{
  return std::forward<Functor>(functor)(std::forward<Args>(args)...);
}

struct Base {};

struct Class : Base
{
  void normal() {}
  void reference()& {}
  int member;
};

struct Derived : Class {};

struct Conversion
{
  Class clazz;

  operator Class&() { return clazz; }
};

struct Pointer
{
  Class clazz;

  Class& operator*() { return clazz; }
};

struct Mixed
{
  Class clazz;

  Class& operator*() { return clazz; }
  operator Class() { throw std::logic_error("Conversion operator invoked for type with operator*"); }
};

static_assert(!is_target_reference<Base&, int Class::*>::value, "checking Base");
static_assert(!is_target_reference<Pointer&, int Class::*>::value, "checking Pointer");
static_assert(!is_target_reference<Mixed&, int Class::*>::value, "checking Mixed");

static_assert(is_target_reference<Class&, int Class::*>::value, "checking Class&");
static_assert(is_target_reference<Class const&, int Class::*>::value, "checking Class const&");
static_assert(is_target_reference<Class&&, int Class::*>::value, "checking Class&");
static_assert(is_target_reference<Class const&&, int Class::*>::value, "checking Class const&&");

static_assert(is_target_reference<Derived&, int Derived::*>::value, "checking Derived&");
static_assert(is_target_reference<Derived const&, int Derived::*>::value, "checking Derived const&");
static_assert(is_target_reference<Derived&&, int Derived::*>::value, "checking Derived&");
static_assert(is_target_reference<Derived const&&, int Derived::*>::value, "checking Derived const&&");

Base base;
Class clazz;
Derived derived;
Class* rawPointer;
Pointer smartPointer;
Conversion conversion;
Mixed mixed;

static_assert(!is_pointer_compatible_with_member_pointer<decltype(base), int Class::*>::value, "checking Base");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(clazz), int Class::*>::value, "checking Class");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(derived), int Class::*>::value, "checking Derived");
static_assert(is_pointer_compatible_with_member_pointer<decltype(rawPointer), int Class::*>::value, "checking RawPointer");
static_assert(is_pointer_compatible_with_member_pointer<decltype(smartPointer), int Class::*>::value, "checking SmartPointer");
static_assert(!is_pointer_compatible_with_member_pointer<decltype(conversion), int Class::*>::value, "checking Conversion");
static_assert(is_pointer_compatible_with_member_pointer<decltype(mixed), int Class::*>::value, "checking Mixed");

static_assert(!is_wrapper_compatible_with_member_pointer<decltype(base), int Class::*>::value, "checking Base");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(clazz), int Class::*>::value, "checking Class");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(derived), int Class::*>::value, "checking Derived");
static_assert(!is_wrapper_compatible_with_member_pointer<decltype(rawPointer), int Class::*>::value, "checking RawPointer");
static_assert(!is_wrapper_compatible_with_member_pointer<decltype(smartPointer), int Class::*>::value, "checking SmartPointer");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(conversion), int Class::*>::value, "checking Conversion");
static_assert(is_wrapper_compatible_with_member_pointer<decltype(mixed), int Class::*>::value, "checking Mixed");


int main()
{
  invoke(&Class::normal, Class{});
  //invoke(&Class::normal, base);
  invoke(&Class::normal, clazz);
  invoke(&Class::normal, derived);
  invoke(&Class::normal, rawPointer);
  invoke(&Class::normal, smartPointer);
  invoke(&Class::normal, conversion);
  invoke(&Class::normal, mixed);

  /* Wont work on gcc 4.8.1 and clang 3.2 because of bug with in implementation
     of is_member_function_pointer for ref qualified methods.
     See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57388
          http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57825
  //invoke(&Class::reference, Class{});
  //invoke(&Class::reference, base);
  invoke(&Class::reference, clazz);
  invoke(&Class::reference, derived);
  invoke(&Class::reference, rawPointer);
  invoke(&Class::reference, smartPointer);
  invoke(&Class::reference, conversion);
  invoke(&Class::reference, mixed);*/

  invoke(&Class::member, Class{});
  //invoke(&Class::member, base);
  invoke(&Class::member, clazz);
  invoke(&Class::member, derived);
  invoke(&Class::member, rawPointer);
  invoke(&Class::member, smartPointer);
  invoke(&Class::member, conversion);
  invoke(&Class::member, mixed);

  invoke([](int) {}, 1);
}

------=_Part_428_16155270.1373059132392--

.


Author: tomaszkam@gmail.com
Date: Tue, 9 Jul 2013 05:58:05 -0700 (PDT)
Raw View
------=_Part_9961_5592082.1373374685374
Content-Type: text/plain; charset=ISO-8859-1



On Friday, July 5, 2013 6:47:13 PM UTC+2, Jonathan Wakely wrote:
>
>
> Making *any* changes to the INVOKE semantics should not be done lightly,
> it's seriously tricky stuff!
>
> I'd like to see some more convincing motivation for this change.
> std::reference_wrapper is a good motivating case, but I'm less sure about
> boost::reference_wrapper ... do you really need another reference_wrapper
> if you have a C++11 implementation?  (I'm aware that the boost one allows
> incomplete types.)   Such wrapper types can always be made to work with
> INVOKE by providing operator* so the last bullet of INVOKE handles them,
> although that's a bit smelly, I admit.
>

Other types that will be addressed by this proposal:
   1. boost::flyweight<T> - similiar to reference_wrapper
   2. std::chrono::duration -
std::mem_fn(&std::chrono::duration<double>::count) will work now with any
duration specialization
For these types the operator* cannot be defined.

--

---
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_9961_5592082.1373374685374
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<br><br>On Friday, July 5, 2013 6:47:13 PM UTC+2, Jonathan Wakely wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;"><div><br>Making *any* changes to =
the INVOKE semantics should not be done lightly, it's seriously tricky stuf=
f!<br><br>I'd like to see some more convincing motivation for this change.&=
nbsp; std::reference_wrapper is a good motivating case, but I'm less sure a=
bout boost::reference_wrapper ... do you really need another reference_wrap=
per if you have a C++11 implementation?&nbsp; (I'm aware that the boost one=
 allows incomplete types.)&nbsp;&nbsp; Such wrapper types can always be mad=
e to work with INVOKE by providing operator* so the last bullet of INVOKE h=
andles them, although that's a bit smelly, I admit.<br></div></blockquote><=
div><br>Other types that will be addressed by this proposal:<br>&nbsp;&nbsp=
; 1. boost::flyweight&lt;T&gt; - similiar to reference_wrapper<br>&nbsp;&nb=
sp; 2. std::chrono::duration - std::mem_fn(&amp;std::chrono::duration&lt;do=
uble&gt;::count) will work now with any duration specialization<br>For thes=
e types the operator* cannot be defined.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_9961_5592082.1373374685374--

.


Author: tomaszkam@gmail.com
Date: Thu, 18 Jul 2013 11:20:46 -0700 (PDT)
Raw View
------=_Part_2022_25690669.1374171646604
Content-Type: multipart/alternative;
 boundary="----=_Part_2023_4650723.1374171646604"

------=_Part_2023_4650723.1374171646604
Content-Type: text/plain; charset=ISO-8859-1

I the attachment you may found the proposal to changed the definition of
INVOKE to support convertible types (also it can be found on github<https://github.com/tomaszkam/proposals/blob/master/Extend%20INVOKE%20to%20support%20types%20convertible%20to%20target%20class.html>).
I will appreciate any feedback on the wording, before I will send it to
assign document number.

On the Alernate proposal - in included this section, because in design
decision I pointed out simpler wording and from my perspective such
statement requires putting actual wording to be compared and assessed by
readers.

--

---
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_2023_4650723.1374171646604
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I the attachment you may found the proposal to changed the definition of IN=
VOKE to support convertible types (also it can be found on <a href=3D"https=
://github.com/tomaszkam/proposals/blob/master/Extend%20INVOKE%20to%20suppor=
t%20types%20convertible%20to%20target%20class.html">github</a>). I will app=
reciate any feedback on the wording, before I will send it to assign docume=
nt number.<br><br>On the Alernate proposal - in included this section, beca=
use in design decision I pointed out simpler wording and from my perspectiv=
e such statement requires putting actual wording to be compared and assesse=
d by readers.<br>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_2023_4650723.1374171646604--
------=_Part_2022_25690669.1374171646604
Content-Type: text/html; charset=UTF-8;
 name="Extend INVOKE to support types convertible to target
 class.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="Extend INVOKE to support types convertible to target
 class.html"
X-Attachment-Id: 9a273de6-22d7-44eb-ae14-4df590b039dd
Content-ID: <9a273de6-22d7-44eb-ae14-4df590b039dd>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/htm=
l4/strict.dtd">
<html><head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8">

<style type=3D"text/css">
pre {margin-left:20pt; }
pre > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
pre > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
..attribute { margin-left: 2em; }
..attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
..attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;=20
  padding-right: 0.4em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;
  padding-right: 0.4em; border: none; }
</style>

<title>Extend INVOKE to support types convertible to target class</title>
<script type=3D"text/javascript">$(function() {
    var next_id =3D 0
    function find_id(node) {
        // Look down the first children of 'node' until we find one
        // with an id. If we don't find one, give 'node' an id and
        // return that.
        var cur =3D node[0];
        while (cur) {
            if (cur.id) return curid;
            if (cur.tagName =3D=3D 'A' && cur.name)
                return cur.name;
            cur =3D cur.firstChild;
        };
        // No id.
        node.attr('id', 'gensection-' + next_id++);
        return node.attr('id');
    };

    // Put a table of contents in the #toc nav.

    // This is a list of <ol> elements, where toc[N] is the list for
    // the current sequence of <h(N+2)> tags. When a header of an
    // existing level is encountered, all higher levels are popped,
    // and an <li> is appended to the level
    var toc =3D [$("<ol/>")];
    $(':header').not('h1').each(function() {
        var header =3D $(this);
        // For each <hN> tag, add a link to the toc at the appropriate
        // level.  When toc is one element too short, start a new list
        var levels =3D {H2: 0, H3: 1, H4: 2, H5: 3, H6: 4};
        var level =3D levels[this.tagName];
        if (typeof level =3D=3D 'undefined') {
            throw 'Unexpected tag: ' + this.tagName;
        }
        // Truncate to the new level.
        toc.splice(level + 1, toc.length);
        if (toc.length < level) {
            // Omit TOC entries for skipped header levels.
            return;
        }
        if (toc.length =3D=3D level) {
            // Add a <ol> to the previous level's last <li> and push
            // it into the array.
            var ol =3D $('<ol/>')
            toc[toc.length - 1].children().last().append(ol);
            toc.push(ol);
        }
        var header_text =3D header.text();
        toc[toc.length - 1].append(
            $('<li/>').append($('<a href=3D"#' + find_id(header) + '"/>')
                              .text(header_text)));
    });
    $('#toc').append(toc[0]);
})
</script>
</head>

<body>

<h1><a name=3D"title">Extend INVOKE to support types convertible to target =
class</a></h1>


<!--p>ISO/IEC JTC1 SC22 WG21 N????</p-->=20
<p>2013-05-27</p>

<address>
Tomasz Kami=C5=84ski, tomaszkam@gmail.com
</address>


<h2><a name=3D"intro">Introduction</a></h2>

<p>This proposal is to extend the definition of <code>INOVKE</code> for cla=
ss member pointers to cover types convertible to a target class of the poin=
ter, like <code>std::reference_wrapper</code>.</p>

<p>Proposal also resolves <a href=3D"http://isocpp.org/files/papers/n3522.h=
tml#2219">LWG issue #2219</a></p>

<!--h2><a name=3D"toc">Table of contents</a></h2-->

<h2><a name=3D"motivation">Motivation and Scope</a></h2>

<p>The standard <code>INOVKE</code> expression models the member pointers a=
s pair of free standing functions, that takes a reference and the pointer (=
including smart pointers) to target class respectively. However there is di=
fference in semantics between the <code>INVOKE</code> expression for member=
 pointers and functors - for member pointers the conversions are not taken =
into consideration in matching of first argument.</p>

<p>This behavior difference prohibit uses wrapper types (ex. <code>std::ref=
erence_wrapper</code>, <code>boost::flyweight</code>) in combination with m=
ember pointers with the standard library functions that are modeled using <=
code>INVOKE</code> (ex. <code>std::bind</code>, <code>std::mem_fn</code>, <=
code>std::async</code>). The aim of this proposal is to fix that usability =
problem via extending definition of <code>INVOKE</code> to allow conversion=
s in such situations.</p>

<p>Proposed change will also cover cases of set of convertible types that m=
odels the same logical entity (ex. std::chrono::duration specializations). =
With the acceptance of this proposal, the <code>std::bind(&amp;std::chrono&=
lt;double&gt;::count, _1)</code> will create functor returning amount of se=
conds for any specialization of std::chrono::duration.</p>

<h3><a name=3D"motivation.deference-operator">Defining <code>operator*</cod=
e></a></h3>

<p>The well know workaround for this problem, is to define the <code>operat=
or*</code> that will return the same result as the conversion operator. Fir=
stly this solution is only applicable in situations when the definition of =
the class can be changed, so it is not feasible for third-party library cla=
sses. Secondly it leads inelegant interface than combines wrapper and point=
er semantics.</p>

<h3><a name=3D"motivation.lambda">Using lambda</a></h3>

<p>The other workaround is to use the lambda expression instead of library =
functions, but in the most cases it leads to the less readable code. Please=
 compare following code snippets:</p>
<pre>
  std::bind([]foo, _1, expr, ref(a));
  [e =3D expr, &amp;a] (auto&amp;&amp; arg) -> decltype(auto) { return foo(=
std::forwrad&lt;decltype(arg)&gt;(arg), e, a); }
</pre>

<h3><a name=3D"motivation.bind-cast">Define special cast functor</a></h3>

<p>In case of <code>bind</code> expressions the problem may be mitigated by=
 introduction of additional cast functor that preforms required casting.</p=
>
<pre>
std::bind(&amp;Class::method, _1)(std::ref(clazz));
std::bind(&amp;Class::method, cast&lt;Class&amp;&gt;(_1))(std::ref(clazz));
</pre>
<p>However this solution depends on <code>std::is_bind_expression</code> tr=
ait and cannot be applied to other library components that depends of <code=
>INOVKE</code> (ex. <code>std::async</code>, <code>std::call_once</code>).<=
/p>

<h2><a name=3D"design">Design Decisions</a></h2>

<p>Allowing conversion in <code>INVOKE</code> with member pointer may lead =
to ambiguity in case of entity <code>t</code>, for which both result of <co=
de>t</code> and <code>*t</code> is implicitly convertible to target class o=
f the pointer.</p>

<p>As example, for the following class:</p>
<pre>
  struct Clazz { int foo; }

  struct Mixed
  {
    Clazz&amp; operator*();
    operator Clazz&amp;();
  };
 =20
  Mixed m;
</pre>
<p>The expression <code>INOVKE(&amp;Clazz::foo, m)</code> may be interprete=
d as <code>static_cast&lt;Clazz&gt;(m).*foo</code> or <code>static_cast&lt;=
Clazz&gt;(*m).*foo</code>. Existence of such in codebase class may be a res=
ult of using <a href=3D"#motivation.deference-operator">work around</a> pre=
sented in the motivation section of this proposal.</p>

<p>There are tree possible behaviors in case of such ambiguity:</p>
  <ol>
    <li>Compilation error</li>
    <li>Preference of <code>operator*</code></li>
    <li>Preference of conversion</li>
  </ol>

<h3><a name=3D"design.error">1. Compilation error</a></h3>

<p>Raising and ambiguity error will make behaviour of <code>INVOKE</code> f=
or member pointers more uniform with behaviour of free standing functions. =
However it will break existing code, that uses entities that are both conve=
rtible to and behaves as a pointer to target class.</p>

<h3><a name=3D"design.prefer-dereference">2. Preference of <code>operator*<=
/code></a></h3>

<p>This is the only option that allow extensions of <code>INVOKE</code> def=
inition without breaking or introducing silent behaviour changes in the exi=
sting code. The minor drawback is that it leads to more complicated definit=
ion of <code>INVOKE</code>.</p>

<h3><a name=3D"design.prefer-conversion">3. Preference of conversion</a></h=
3>

<p>Preference of the conversion leads to the silent behaviour change of the=
 existing C++11 standard compliant code, so this option should not be consi=
dered as a feasible solution.</p>

<h3><a name=3D"design.summary">Summary</a></h3>

<p>This proposal recommends implementing the second option and provides the=
 wording in the <a href=3D"#wording">Proposed wording</a> section. The word=
ing for the first option may be found in the <a href=3D"#alternate">Alterna=
te proposal</a> section. Third option is not further discussed.</p>

<h2><a name=3D"standard">Impact On The Standard</a></h2>

<p>This proposal has no dependencies beyond a C++11 compiler and Standard L=
ibrary implementation. (It depends on perfect forwarding, varidatic templat=
es, <code>decltype</code> and trailing return types.)</p>

<p>Nothing depends on this proposal.</p>

<h2><a name=3D"wording">Proposed wording</a></h2>

<p>Change the paragraph 20.10.2 Requirments [func.require].</p>
 =20
<blockquote class=3D"std">
  <dl class=3D"attribute">
    =20
    <dd><p>Viable reference types for member pointer <code>p</code> of type=
 <code>M T::*</code> are:
    </p><ul>
      <li><code>T cv&amp;</code>, <code>T cv&amp;&amp;</code> for all possi=
ble cv-qualifiers <code>cv</code> if <code>M</code> is not function type,</=
li>
      <li><code>T cv&amp;</code>, <code>T cv&amp;&amp;</code> if <code>M</c=
ode> is function type without ref-qualifier and with cv-qualifiers <code>cv=
</code>,</li>
      <li><code>T cv ref</code> if <code>M</code> is function type with ref=
-qualifier <code>ref</code> and cv-qualifiers <code>cv</code>.</li>
    </ul><p></p></dd>

    <dd><p>Define <code>INVOKE(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class =
<code>T</code> and <code>TR</code> is viable reference type for <code>f</co=
de>:
        <ul>
          <li><code>(t1.*f)(t2, ..., tN)</code> when <code>t1</code> is an =
object of type <code>T</code> or a reference to an object of type <code>T</=
code> or a reference to an object of a type derived from <code>T</code>;</l=
i>
          <li><code>(static_cast&lt;TR&gt;(*t1).*f)(t2, ..., tN)</code> whe=
n <code>t1</code> does not fulfill criteria of any of previous point and <c=
ode>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>(static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN)</code> when=
 <code>t1</code> does not fulfill criteria of any of previous point and <co=
de>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>=
T</code> and <code>N =3D=3D 1</code> and <code>TR</code> is viable referenc=
e type for <code>f</code>:
        <ul>
          <li><code>t1.*f</code> when <code>t1</code> is an object of type =
<code>T</code> or a reference to an object of type <code>T</code> or a refe=
rence to an object of a type derived from <code>T</code>;</li>
          <li><code>static_cast&lt;TR&gt;(*t1).*f</code> when <code>t1</cod=
e> does not fulfill criteria of any of previous point and <code>*t1</code> =
is implicitly convertible to <code>TR</code>;</li>
          <li><code>static_cast&lt;TR&gt;(t1).*f</code> when <code>t1</code=
> does not fulfill criteria of any of previous point and <code>t1</code> is=
 implicitly convertible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name=3D"alternate">Alternate proposal</a></h2>

<p>Change the paragraph 20.10.2 Requirments [func.require].</p>
 =20
<blockquote class=3D"std">
  <dl class=3D"attribute">
    =20
    <dd><p>Viable reference types for member pointer <code>p</code> of type=
 <code>M T::*</code> are:
    </p><ul>
      <li><code>T cv&amp;</code>, <code>T cv&amp;&amp;</code> for all possi=
ble cv-qualifiers <code>cv</code> if <code>M</code> is not function type,</=
li>
      <li><code>T cv&amp;</code>, <code>T cv&amp;&amp;</code> if <code>M</c=
ode> is function type without ref-qualifier and with cv-qualifiers <code>cv=
</code>,</li>
      <li><code>T cv ref</code> if <code>M</code> is function type with ref=
-qualifier <code>ref</code> and cv-qualifiers <code>cv</code>.</li>
    </ul><p></p></dd>

    <dd><p>Define <code>INVOKE(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class =
<code>T</code> and <code>TR</code> is viable reference type for <code>f</co=
de>:
        <ul>
          <li><code>(static_cast&lt;TR&gt;(t1).*f)(t2, ..., tN)</code> when=
 <code>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>(static_cast&lt;TR&gt;(*t1).*f)(t2, ..., tN)</code> whe=
n <code>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above po=
ints applies;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>=
T</code> and <code>N =3D=3D 1</code> and <code>TR</code> is viable referenc=
e type for <code>f</code>:
        <ul>
          <li><code>static_cast&lt;TR&gt;(t1).*f</code> when <code>t1</code=
> is implicitly convertible to <code>TR</code>;</li>
          <li><code>static_cast&lt;TR&gt;(*t1).*f</code> when <code>*t1</co=
de> is implicitly convertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above po=
ints applies;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name=3D'implementability'>Implementability</a></h2>

<p>Proposed change can be implemented as pure library extension in C++11. I=
mplementation of <code>invoke</code> function that conforms proposed wordin=
g can be found <a href=3D"https://github.com/tomaszkam/proposals/tree/maste=
r/invoke">https://github.com/tomaszkam/proposals/tree/master/invoke</a>.</p=
>

<h2><a name=3D"acknowledgements">Acknowledgements</a></h2>

<p>Tomasz Mi=C4=85sko offered many useful suggestions and corrections to th=
e proposal.</p>
<p>Ville Voutilainen, Gabriel Dos Reis and other people in discussion group=
 <a href=3D"https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic=
/std-proposals/FtilAt9V_1c">ISO C++ Standard - Future Proposals</a> provide=
d numerous insightful suggestions.</p>

<h2><a name=3D"literature">References</a></h2>

<ol>

<li>Alisdair Meredith, "C++ Standard Library Active Issues List (Revision R=
82)" (N3522, <a href=3D"http://isocpp.org/files/papers/n3522.html">http://i=
socpp.org/files/papers/n3522.html</a>)</li>
<li>Tomasz Kami=C5=84ski, Implementation of invoke function (<a href=3D"htt=
ps://github.com/tomaszkam/proposals/tree/master/invoke">https://github.com/=
tomaszkam/proposals/tree/master/invoke</a>)</li>

</ol>

</body></html>

------=_Part_2022_25690669.1374171646604--

.


Author: tomaszkam@gmail.com
Date: Sat, 17 Aug 2013 08:07:44 -0700 (PDT)
Raw View
------=_Part_3821_18804118.1376752064046
Content-Type: multipart/alternative;
 boundary="----=_Part_3822_12421516.1376752064046"

------=_Part_3822_12421516.1376752064046
Content-Type: text/plain; charset=ISO-8859-1

I have changed occurrences of static_cast<TR>(expr) to TR{expr}, to avoid
unnecessary suggestions that down-cast can be performed by proposed invoke.

--

---
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_3822_12421516.1376752064046
Content-Type: text/html; charset=ISO-8859-1

<div dir="ltr">I have changed occurrences of static_cast&lt;TR&gt;(expr) to TR{expr}, to avoid unnecessary suggestions that down-cast can be performed by proposed invoke.<br></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an 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 />

------=_Part_3822_12421516.1376752064046--
------=_Part_3821_18804118.1376752064046
Content-Type: text/html; charset=UTF-8;
 name="Extend INVOKE to support types convertible to target
 class.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="Extend INVOKE to support types convertible to target
 class.html"
X-Attachment-Id: 3784070a-5491-4a18-a44d-8f37cb810bc9
Content-ID: <3784070a-5491-4a18-a44d-8f37cb810bc9>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/htm=
l4/strict.dtd">
<html><head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8">

<style type=3D"text/css">
pre {margin-left:20pt; }
pre > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
pre > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
..attribute { margin-left: 2em; }
..attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
..attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table.header { border: 0px; border-spacing: 0;
  margin-left: 0px; font-style: normal; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;=20
  padding-right: 0.4em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;
  padding-right: 0.4em; border: none; }
</style>

<title>Extend INVOKE to support types convertible to target class</title>
<script type=3D"text/javascript">$(function() {
    var next_id =3D 0
    function find_id(node) {
        // Look down the first children of 'node' until we find one
        // with an id. If we don't find one, give 'node' an id and
        // return that.
        var cur =3D node[0];
        while (cur) {
            if (cur.id) return curid;
            if (cur.tagName =3D=3D 'A' && cur.name)
                return cur.name;
            cur =3D cur.firstChild;
        };
        // No id.
        node.attr('id', 'gensection-' + next_id++);
        return node.attr('id');
    };

    // Put a table of contents in the #toc nav.

    // This is a list of <ol> elements, where toc[N] is the list for
    // the current sequence of <h(N+2)> tags. When a header of an
    // existing level is encountered, all higher levels are popped,
    // and an <li> is appended to the level
    var toc =3D [$("<ol/>")];
    $(':header').not('h1').each(function() {
        var header =3D $(this);
        // For each <hN> tag, add a link to the toc at the appropriate
        // level.  When toc is one element too short, start a new list
        var levels =3D {H2: 0, H3: 1, H4: 2, H5: 3, H6: 4};
        var level =3D levels[this.tagName];
        if (typeof level =3D=3D 'undefined') {
            throw 'Unexpected tag: ' + this.tagName;
        }
        // Truncate to the new level.
        toc.splice(level + 1, toc.length);
        if (toc.length < level) {
            // Omit TOC entries for skipped header levels.
            return;
        }
        if (toc.length =3D=3D level) {
            // Add a <ol> to the previous level's last <li> and push
            // it into the array.
            var ol =3D $('<ol/>')
            toc[toc.length - 1].children().last().append(ol);
            toc.push(ol);
        }
        var header_text =3D header.text();
        toc[toc.length - 1].append(
            $('<li/>').append($('<a href=3D"#' + find_id(header) + '"/>')
                              .text(header_text)));
    });
    $('#toc').append(toc[0]);
})
</script>
</head>

<body>

<table class=3D"header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;<th> <td></td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;<th> <td>2013-08-17</td>
  </tr>
  <tr>
    <th>Project:&nbsp;&nbsp;<th> <td>Programming Language C++, Library Work=
ing Group</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;<th> <td><address>Tomasz Kami=C5=84ski &lt;tom=
aszkam at gmail dot com&gt;</address></td>
  </tr>
</tbody></table>

<h1><a name=3D"title">Extend INVOKE to support types convertible to target =
class</a></h1>

<h2><a name=3D"intro">Introduction</a></h2>

<p>This proposal is to extend the definition of <code><em>INVOKE</em></code=
> for class member pointers to cover types convertible to a target class of=
 the pointer, like <code>std::reference_wrapper</code>.</p>

<p>Proposal also resolves <a href=3D"http://isocpp.org/files/papers/n3522.h=
tml#2219">LWG issue #2219</a></p>

<!--h2><a name=3D"toc">Table of contents</a></h2-->

<h2><a name=3D"motivation">Motivation and Scope</a></h2>

<p>The standard <code><em>INVOKE</em></code> expression models the member p=
ointers as pair of free standing functions, that takes a reference and the =
pointer (including smart pointers) to target class respectively. However th=
ere is difference in semantics between the <code><em>INVOKE</em></code> exp=
ression for member pointers and functors - for member pointers the conversi=
ons are not taken into consideration in matching of first argument.</p>

<p>This behavior difference prohibit uses wrapper types (e.g., <code>std::r=
eference_wrapper</code>, <code>boost::flyweight</code>) in combination with=
 member pointers with the standard library functions that are modeled using=
 <code><em>INVOKE</em></code> (e.g., <code>std::bind</code>, <code>std::mem=
_fn</code>, <code>std::async</code>). The aim of this proposal is to fix th=
at usability problem via extending definition of <code><em>INVOKE</em></cod=
e> to allow implicit conversions in such situations.</p>

<p>Proposed change will also cover cases of set of convertible types that m=
odels the same logical entity (e.g., std::chrono::duration specializations)=
.. With the acceptance of this proposal, the <code>std::bind(&amp;std::chron=
o&lt;double&gt;::count, _1)</code> will create functor returning amount of =
seconds for any specialization of std::chrono::duration.</p>

<h3><a name=3D"motivation.deference-operator">Defining <code>operator*</cod=
e></a></h3>

<p>The well know workaround for this problem, is to define the <code>operat=
or*</code> that will return the same result as the conversion operator. Fir=
stly this solution is only applicable in situations when the definition of =
the class can be changed, so it is not feasible for third-party library cla=
sses. Secondly it leads inelegant interface than combines wrapper and point=
er semantics.</p>

<h3><a name=3D"motivation.lambda">Using lambda</a></h3>

<p>The other workaround is to use the lambda expression instead of library =
functions, but in the most cases it leads to the less readable code. Please=
 compare following code snippets:</p>
<pre>
  std::bind(&amp;foo, _1, expr, ref(a));
  [e =3D expr, &amp;a] (auto&amp;&amp; arg) -> decltype(auto) { return foo(=
std::forward&lt;decltype(arg)&gt;(arg), e, a); }
</pre>

<h3><a name=3D"motivation.bind-cast">Define special cast functor</a></h3>

<p>In case of <code>bind</code> expressions the problem may be mitigated by=
 introduction of additional cast functor that preforms required casting.</p=
>
<pre>
std::bind(&amp;Class::method, _1)(std::ref(clazz));
std::bind(&amp;Class::method, cast&lt;Class&amp;&gt;(_1))(std::ref(clazz));
</pre>
<p>However this solution depends on <code>std::is_bind_expression</code> tr=
ait and cannot be applied to other library components that depends of <code=
><em>INVOKE</em></code> (e.g., <code>std::async</code>, <code>std::call_onc=
e</code>).</p>

<h2><a name=3D"design">Design Decisions</a></h2>

<p>Allowing conversion in <code><em>INVOKE</em></code> with member pointer =
may lead to ambiguity in case of entity <code>t</code>, for which both resu=
lt of <code>t</code> and <code>*t</code> is implicitly convertible to targe=
t class of the pointer.</p>

<p>As example, for the following class:</p>
<pre>
  struct Clazz { int foo; }

  struct Mixed
  {
    Clazz&amp; operator*();
    operator Clazz&amp;();
  };
 =20
  Mixed m;
</pre>
<p>The expression <code><em>INVOKE</em>(&amp;Clazz::foo, m)</code> may be i=
nterpreted as <code>static_cast&lt;Clazz&gt;(m).*foo</code> or <code>static=
_cast&lt;Clazz&gt;(*m).*foo</code>. Existence of such in codebase class may=
 be a result of using <a href=3D"#motivation.deference-operator">work aroun=
d</a> presented in the motivation section of this proposal.</p>

<p>There are tree possible behaviors in case of such ambiguity:</p>
  <ol>
    <li>Compilation error</li>
    <li>Preference of <code>operator*</code></li>
    <li>Preference of conversion</li>
  </ol>

<h3><a name=3D"design.error">1. Compilation error</a></h3>

<p>Raising and ambiguity error will make behaviour of <code><em>INVOKE</em>=
</code> for member pointers more uniform with behaviour of free standing fu=
nctions. However it will break existing code, that uses entities that are b=
oth convertible to and behaves as a pointer to target class.</p>

<h3><a name=3D"design.prefer-dereference">2. Preference of <code>operator*<=
/code></a></h3>

<p>This is the only option that allow extensions of <code><em>INVOKE</em></=
code> definition without breaking or introducing silent behaviour changes i=
n the existing code. The minor drawback is that it leads to more complicate=
d definition of <code><em>INVOKE</em></code>.</p>

<h3><a name=3D"design.prefer-conversion">3. Preference of conversion</a></h=
3>

<p>Preference of the conversion leads to the silent behaviour change of the=
 existing C++11 standard compliant code, so this option should not be consi=
dered as a feasible solution.</p>

<h3><a name=3D"design.summary">Summary</a></h3>

<p>This proposal recommends implementing the second option and provides the=
 wording in the <a href=3D"#wording">Proposed wording</a> section. The word=
ing for the first option may be found in the <a href=3D"#alternate">Alterna=
te proposal</a> section. Third option is not further discussed.</p>

<h2><a name=3D"standard">Impact On The Standard</a></h2>

<p>This proposal has no dependencies beyond a C++11 compiler and Standard L=
ibrary implementation. (It depends on perfect forwarding, varidatic templat=
es, <code>decltype</code> and trailing return types.)</p>

<p>Nothing depends on this proposal.</p>

<h2><a name=3D"wording">Proposed wording</a></h2>

<p>Change the paragraph 20.10.2 Requirements [func.require].</p>

<blockquote class=3D"stddel">
  <dl class=3D"attribute">
    =20
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follo=
ws:
    </p><ul>
      <li><code>(t1.*f)(t2, ..., tN)</code> when <code>f</code> is a pointe=
r to a member function of a class <code>T</code> and <code>t1</code> is an =
object of type <code>T</code> or a reference to an object of type <code>T</=
code> or a reference to an object of a type derived from <code>T</code>;</l=
i>
      <li><code>((*t1).*f)(t2, ..., tN)</code> when <code>f</code> is a poi=
nter to a member function of a class <code>T</code> and <code>t1</code> is =
not one of the types described in the previous item;</li>
      <li><code>t1.*f</code> when <code>N =3D=3D 1</code> and <code>f</code=
> is a pointer to member data of a class <code>T</code> and <code>t1</code>=
 is an object of type <code>T</code> or a reference to an object of type <c=
ode>T</code> or a reference to an object of a type derived from <code>T</co=
de>;</li>
      <li><code>(*t1).*f</code> when <code>N =3D=3D 1</code> and <code>f</c=
ode> is a pointer to member data of a class <code>T</code> and <code>t1</co=
de> is not one of the types described in the previous item;</li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>
 =20
<blockquote class=3D"stdins">
  <dl class=3D"attribute">
    =20
    <dd><p>Define <em>viable reference types</em> for member pointer <code>=
p</code> of type <code>M T::*</code> as:
    </p><ul>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</c=
ode> for all possible cv-qualifiers <code><em>cv</em></code> if <code>M</co=
de> is not function type,</li>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</c=
ode> if <code>M</code> is function type without ref-qualifier and with cv-q=
ualifiers <code><em>cv</em></code>,</li>
      <li><code>T <em>cv</em> <em>ref</em></code> if <code>M</code> is func=
tion type with ref-qualifier <code><em>ref</em></code> and cv-qualifiers <c=
ode><em>cv</em></code>.</li>
    </ul><p></p></dd>

    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follo=
ws:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class =
<code>T</code> and <code>TR</code> is <em>viable reference type</em> for <c=
ode>f</code>:
        <ul>
          <li><code>(t1.*f)(t2, ..., tN)</code> when <code>t1</code> is an =
object of type <code>T</code> or a reference to an object of type <code>T</=
code> or a reference to an object of a type derived from <code>T</code>;</l=
i>
          <li><code>(TR{*t1}.*f)(t2, ..., tN)</code> when <code>t1</code> d=
oes not fulfill criteria of any of previous point and <code>*t1</code> is i=
mplicitly convertible to <code>TR</code>;</li>
          <li><code>(TR{t1}.*f)(t2, ..., tN)</code> when <code>t1</code> do=
es not fulfill criteria of any of previous point and <code>t1</code> is imp=
licitly convertible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>=
T</code> and <code>N =3D=3D 1</code> and <code>TR</code> is <em>viable refe=
rence type</em> for <code>f</code>:
        <ul>
          <li><code>t1.*f</code> when <code>t1</code> is an object of type =
<code>T</code> or a reference to an object of type <code>T</code> or a refe=
rence to an object of a type derived from <code>T</code>;</li>
          <li><code>TR{*t1}.*f</code> when <code>t1</code> does not fulfill=
 criteria of any of previous point and <code>*t1</code> is implicitly conve=
rtible to <code>TR</code>;</li>
          <li><code>TR{t1}.*f</code> when <code>t1</code> does not fulfill =
criteria of any of previous point and <code>t1</code> is implicitly convert=
ible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name=3D"alternate">Alternate proposal</a></h2>

<p>Change the paragraph 20.10.2 Requirements [func.require].</p>

<blockquote class=3D"stddel">
  <dl class=3D"attribute">
    =20
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follo=
ws:
    </p><ul>
      <li><code>(t1.*f)(t2, ..., tN)</code> when <code>f</code> is a pointe=
r to a member function of a class <code>T</code> and <code>t1</code> is an =
object of type <code>T</code> or a reference to an object of type <code>T</=
code> or a reference to an object of a type derived from <code>T</code>;</l=
i>
      <li><code>((*t1).*f)(t2, ..., tN)</code> when <code>f</code> is a poi=
nter to a member function of a class <code>T</code> and <code>t1</code> is =
not one of the types described in the previous item;</li>
      <li><code>t1.*f</code> when <code>N =3D=3D 1</code> and <code>f</code=
> is a pointer to member data of a class <code>T</code> and <code>t1</code>=
 is an object of type <code>T</code> or a reference to an object of type <c=
ode>T</code> or a reference to an object of a type derived from <code>T</co=
de>;</li>
      <li><code>(*t1).*f</code> when <code>N =3D=3D 1</code> and <code>f</c=
ode> is a pointer to member data of a class <code>T</code> and <code>t1</co=
de> is not one of the types described in the previous item;</li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>
 =20
<blockquote class=3D"stdins">
  <dl class=3D"attribute">
=20
    <dd><p>Define <em>viable reference types</em> for member pointer <code>=
p</code> of type <code>M T::*</code> as:
    </p><ul>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</c=
ode> for all possible cv-qualifiers <code><em>cv</em></code> if <code>M</co=
de> is not function type,</li>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</c=
ode> if <code>M</code> is function type without ref-qualifier and with cv-q=
ualifiers <code><em>cv</em></code>,</li>
      <li><code>T <em>cv</em> <em>ref</em></code> if <code>M</code> is func=
tion type with ref-qualifier <code><em>ref</em></code> and cv-qualifiers <c=
ode><em>cv</em></code>.</li>
    </ul><p></p></dd>
  =20
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follo=
ws:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class =
<code>T</code> and <code>TR</code> is <em>viable reference type</em> for <c=
ode>f</code>:
        <ul>
          <li><code>(TR{t1}.*f)(t2, ..., tN)</code> when <code>t1</code> is=
 implicitly convertible to <code>TR</code>;</li>
          <li><code>(TR{*t1}.*f)(t2, ..., tN)</code> when <code>*t1</code> =
is implicitly convertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above po=
ints applies;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>=
T</code> and <code>N =3D=3D 1</code> and <code>TR</code> is <em>viable refe=
rence type</em> for <code>f</code>:
        <ul>
          <li><code>TR{t1}.*f</code> when <code>t1</code> is implicitly con=
vertible to <code>TR</code>;</li>
          <li><code>TR{*t1}.*f</code> when <code>*t1</code> is implicitly c=
onvertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above po=
ints applies;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name=3D'implementability'>Implementability</a></h2>

<p>Proposed change can be implemented as pure library extension in C++11. I=
mplementation of <code>invoke</code> function that conforms proposed wordin=
g can be found <a href=3D"https://github.com/tomaszkam/proposals/tree/maste=
r/invoke">https://github.com/tomaszkam/proposals/tree/master/invoke</a>.</p=
>

<h2><a name=3D"acknowledgements">Acknowledgements</a></h2>

<p>Tomasz Mi=C4=85sko and Mikhail Semenov offered many useful suggestions a=
nd corrections to the proposal.</p>
<p>Ville Voutilainen, Gabriel Dos Reis and other people in discussion group=
 <a href=3D"https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic=
/std-proposals/FtilAt9V_1c">ISO C++ Standard - Future Proposals</a> provide=
d numerous insightful suggestions.</p>

<h2><a name=3D"literature">References</a></h2>

<ol>

<li>Alisdair Meredith, "C++ Standard Library Active Issues List (Revision R=
82)" (N3522, <a href=3D"http://isocpp.org/files/papers/n3522.html">http://i=
socpp.org/files/papers/n3522.html</a>)</li>
<li>Tomasz Kami=C5=84ski, Implementation of invoke function (<a href=3D"htt=
ps://github.com/tomaszkam/proposals/tree/master/invoke">https://github.com/=
tomaszkam/proposals/tree/master/invoke</a>)</li>

</ol>

</body></html>

------=_Part_3821_18804118.1376752064046--

.