Title
INVOKE-ing a pointer to member with a reference_wrapper as the object expression
Status
c++17
Section
[func.require]
Submitter
Jonathan Wakely

Created on 2012-11-28.00:00:00 last changed 89 months ago

Messages

Date: 2015-05-05.20:56:00

Proposed resolution:

This wording is relative to N3936.

  1. Change [func.require] p1 as depicted:

    Define INVOKE(f, t1, t2, ..., tN) as follows:

    • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from Tis_base_of<T, decay_t<decltype(t1)>>::value is true;

    • (t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of a class T and decay_t<decltype(t1)> is a specialization of reference_wrapper;

    • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous itemdoes not satisfy the previous two items;

    • t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from Tis_base_of<T, decay_t<decltype(t1)>>::value is true;

    • t1.get().*f when N == 1 and f is a pointer to member data of a class T and decay_t<decltype(t1)> is a specialization of reference_wrapper;

    • (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous itemdoes not satisfy the previous two items;

    • f(t1, t2, ..., tN) in all other cases.

Date: 2015-05-05.20:56:00

[ 2015-05, Lenexa ]

STL: latest note from Cologne, waiting for implementation experience
STL: don't think this is harder than anything else we do
MC: it does involve mem_fn and invoke
STL: my simplication was not to attempt fine-grained
STL: can ignore pmf
STL: can't invoke pmf to reference wrapper
STL: wording dated back to TR1 when there was no decltype
MC: should decay_t<decltype(t1)> be pulled out since it is in multiple places
STL: it could be handled editorially
STL: we fix function, bind, invoke
STL: have not implemented this but believe it is fine
MC: Eric F, you have worked in invoke
EF: yes, looks ok
MC: consensus move to ready

Date: 2015-03-29.14:22:12

[ 2015-02, Cologne ]

Waiting for implementation experience.

Date: 2014-10-15.00:00:00

[ 2014-10-01, STL adds discussion and provides an improved resolution ]

Because neither t1.*f nor (*t1).*f will compile when t1 is reference_wrapper<U> for any U, we don't need to inspect U carefully. We can bluntly detect all reference_wrappers and use get() for them.

We would have to be more careful if we had to deal with pointers to members of reference_wrapper itself. Fortunately, we don't. First, it doesn't have user-visible data members. Second, users technically can't take the addresses of its member functions (this is a consequence of [member.functions], the Implementer's Best Friend).

While we're in the neighborhood, I recommend simplifying and clarifying the wording used to detect base/derived objects.

Previous resolution from Mike Spertus [SUPERSEDED]:

This wording is relative to N3936.

  1. Edit [func.require]:

    Define INVOKE(f, t1, t2, ..., tN) as follows:

    • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

    • (t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of class T and t1 is an object of type reference_wrapper<U> where U is either the type T or a type derived from T.

    • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

    • t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

    • t1.get().*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type reference_wrapper<U> where U is either the type T or a type derived from T.

    • (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

    • f(t1, t2, ..., tN) in all other cases.

Date: 2014-02-15.00:00:00

[ 2014-02-14, Issaquah, Mike Spertus supplies wording ]

Previous resolution from Jonathan [SUPERSEDED]:

This wording is relative to N3485.

  1. Edit [func.require]:

    Define INVOKE(f, t1, t2, ..., tN) as follows:

    • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T U or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;

    • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

    • t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T U or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;

    • (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

    • f(t1, t2, ..., tN) in all other cases.

Date: 2013-04-15.00:00:00

[ 2013-04-18, Bristol ]

Jonathan comments:

In the proposed resolution in the first bullet (t1.*f) is not valid if t1 is a reference_wrapper, so we probably need a separate bullet to handle the reference_wrapper case.

Date: 2013-03-15.00:00:00

[ 2013-03-15 Issues Teleconference ]

Moved to Review.

The wording seems accurate, but verbose. If possible, we would like to define the kind of thing being specified so carefully as one of a number of potential language constructs in a single place. It is also possible that this clause is that single place.

Date: 2012-11-28.00:00:00

The standard currently requires this to be invalid:

#include <functional>

struct X { int i; } x;
auto f = &X::i;
auto t1 = std::ref(x);
int i = std::mem_fn(f)(t1);

The call expression on the last line is equivalent to INVOKE(f, std::ref(x)) which according to [func.require]p1 results in the invalid expression (*t1).*f because reference_wrapper<X> is neither an object of type X nor a reference to an object of type X nor a reference to an object of a type derived from X.

The same argument applies to pointers to member functions, and if they don't work with INVOKE it becomes harder to do all sorts of things such as:

call_once(o, &std::thread::join, std::ref(thr))

or

async(&std::list<int>::sort, std::ref(list));

The definition of INVOKE should be extended to handle reference wrappers.

History
Date User Action Args
2017-07-30 20:15:43adminsetstatus: wp -> c++17
2015-10-27 16:52:45adminsetstatus: ready -> wp
2015-05-05 20:56:00adminsetmessages: + msg7358
2015-05-05 20:56:00adminsetstatus: open -> ready
2015-03-29 14:22:12adminsetmessages: + msg7262
2014-10-09 19:24:42adminsetmessages: + msg7144
2014-02-15 01:58:13adminsetmessages: + msg6874
2013-04-18 22:58:13adminsetmessages: + msg6463
2013-04-18 22:58:13adminsetstatus: review -> open
2013-03-18 14:33:00adminsetmessages: + msg6430
2013-03-18 13:02:36adminsetstatus: new -> review
2012-11-28 23:12:19adminsetmessages: + msg6290
2012-11-28 00:00:00admincreate