Section: 22.10.16 [func.memfn], 22.10.13 [func.not.fn], 22.10.15 [func.bind] Status: Resolved Submitter: Detlef Vollmann Opened: 2017-10-07 Last modified: 2021-06-06
Priority: 3
View all other issues in [func.memfn].
View all issues with Resolved status.
Discussion:
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()
.
call_wrapper
object is a
simple call wrapper.
[2017-11 Albuquerque Wednesday night issues processing]
Priority set to 3. Tomasz to write a paper that will address this issue. See also 3015
[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.
[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.
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.
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)
andf(1)
have the same type. — end note]
[2020-01 Resolved by the adoption of P1065 in Cologne.]
Proposed resolution: