This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2219. `INVOKE`-ing a pointer to member with a `reference_wrapper` as the object expression

Section: 20.14.4 [func.require] Status: C++17 Submitter: Jonathan Wakely Opened: 2012-11-28 Last modified: 2017-07-30

Priority: 2

View all other issues in [func.require].

View all issues with C++17 status.

Discussion:

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 20.14.4 [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.

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

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

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

Previous resolution from Jonathan [SUPERSEDED]:

> This wording is relative to N3485.

> 1. Edit 20.14.4 [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.

[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_wrapper`s 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 16.4.6.5 [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 20.14.4 [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.

[2015-02, Cologne]

Waiting for implementation experience.

[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

Proposed resolution:

This wording is relative to N3936.

1. Change 20.14.4 [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 `T` `is_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 item does 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 `T` `is_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 item does not satisfy the previous two items;

   > - `f(t1, t2, ..., tN)` in all other cases.