Title
Clarify unspecified call wrappers
Status
new
Section
[func.memfn][func.not_fn][func.bind]
Submitter
Detlef Vollmann

Created on 2017-10-07.00:00:00, last changed 2019-05-12.15:32:33.

Messages

Date: 2019-05-12.15:32:33

Proposed resolution:

This wording is relative to N4700.

  1. After section [expos.only.types] "Exposition-only types" add the following new section:

    ?.?.?.?.? unspecified types [unspecified.types]

    [Note: Whenever the return type of a function template is declared as unspecified, the return type depends only on the template arguments of the specialization. Given the example:

    template<class T> unspecified f(T);
    

    the expressions f(0) and f(1) have the same type. — end note]

Date: 2019-05-15.00:00:00

[ 2019-05-12; Tomasz comments ]

I have realized that this issue indicates an real problem with the usability of bind as the replacement of the binder1st/binder2nd. Currently it is not required that a binding functor of the same type with same argument, produces the same result, as the type of the call wrapper may depend on the cv ref qualifiers of arguments. For example we are not requiring that the types of f1, f2, f3, f4 are the same (and actually they are not for clang):

auto func = [](std::string) {};
std::string s("foo");
auto f1 = std::bind(func, s);
auto f2 = std::bind(std::as_const(func), std::as_const(s));
auto f3 = std::bind(func, std::string("bar"));
auto f4 = std::bind(std::move(func), std::move(s));
// online link: https://wandbox.org/permlink/dcXJaITMJCnBWt7R

As a consequence, if the user creates a std::vector<decltype(std::bind(func, std::string(), _2))> (instead of std::vector<std::binder1st<FuncType, std::string>>) he may not be able to store the result of the binding func with std::string instance, if an copy of std::string is made. That leads me to conclusion that this issue actually require wording change, to provide such guarantee, and is materially different from LWG 3015.

During migration from std::bind1st/std::bind2nd (removed in C++17) to std::bind, the user may need to replace std::binder1st/std::binder2nd with an appropriate decltype of std::bind invocation. For example:

FuncType func; std::string s;

std::vector<std::binder1st<FuncType>> v;
v.push_back(std::bind1st(func, s));
v.push_back(std::bind1st(func, std::string("text")));
needs to be replaced with:
std::vector<decltype(std::bind(func, s, _1))> v;
v.push_back(std::bind(func, s, _1));
v.push_back(std::bind(func, std::string("text"), _1));

but the last statement is not guaranteed to be well-formed.

Therefore I would like to withdraw my previously suggested wording change.

Previous resolution [SUPERSEDED]:

This wording is relative to N4700.

  1. After section [expos.only.types] "Exposition-only types" add the following new section:

    ?.?.?.?.? unspecified types [unspecified.types]

    [Note: Whenever the return type of a function template is declared as unspecified, the return type depends only on the template arguments of the specialization. Given the example:

    template<class T> unspecified f(T);
    

    the expressions f(0) and f(1) have the same type. — end note]

Date: 2017-11-15.00:00:00

[ 2017-11-10, Tomasz comments and provides wording together with STL ]

From the core language rules it is already required that same function template specialization have the same return type. Given that the invocation of mem_fn/bind/not_fn will always return the same wrapper type, if they are instantiated (called with) same parameters type. However, the existence of this issue, shows that some library-wide clarification note would be welcomed.

Date: 2017-11-09.15:13:04

[ 2017-11 Albuquerque Wednesday night issues processing ]

Priority set to 3. Tomasz to write a paper that will address this issue. See also 3015

Date: 2017-10-07.00:00:00

Even after the discussion on the reflector, starting with this reflector message it's not completely clear that unspecified as return type of mem_fn really means 'unspecified, but always the same'. The same problem exists for bind() and not_fn().

Possible solution:

Specify in [func.def] or [func.require] that a call wrapper type is always the same for forwarding call wrappers if the object is returned by a function with the same parameter types. And also put into [func.not_fn] that a call_wrapper object is a simple call wrapper.

History
Date User Action Args
2019-05-12 15:32:33adminsetmessages: + msg10405
2017-11-10 18:21:29adminsetmessages: + msg9545
2017-11-10 18:21:29adminsetmessages: + msg9544
2017-11-09 15:13:04adminsetmessages: + msg9522
2017-10-07 00:00:00admincreate