Consider the following code:
struct A {
int& getAttribute();
const int& getAttribute() const;
};
std::vector<int> foo(const std::vector<A>& as) {
std::vector<int> ints;
std::transform(as.begin(), as.end(), std::back_inserter(ints),
std::mem_fn(&A::getAttribute));
return ints;
}
Its compilation (g++ -std=c++14 -c mem_fn.cpp
, g++ version 7.5.0) fails with the following error:
error: no matching function for call to
‘mem_fn(<unresolved overloaded function type>)’
However,
const int& getAttribute() const
method, the compilation succeedsint& getAttribute()
method, the compilation fails with the following error messages:
/usr/include/c++/7/bits/stl_algo.h:4306:24:
error: no match for call to
‘(std::_Mem_fn<int& (A::*)()>) (const A&)’
/usr/include/c++/7/functional:174:27:
error: no matching function for call to
‘__invoke(int& (A::* const&)(), const A&)’
/usr/include/c++/7/bits/invoke.h:89:5:
error: no type named ‘type’ in
‘struct std::__invoke_result<int& (A::* const&)(), const A&>’
Alternatively, we could use a lambda here or help the compiler by explicitly specifying the type of a matching method as mem_fn
's template argument:
std::mem_fn<const int& () const>(&A::getAttribute)
.
So, it looks like, as the int& getAttribute()
method does not fit, the const int& getAttribute() const
method is the one that should have been choosen by the by the compiler in the original code.
Why does compiler fail to select it and report the <unresolved overloaded function type>
error?
The compiler should choose pointer of the function at the moment of mem_fn
creation. It can only look at the std::mem_fn(&A::getAttribute)
expression, but cannot look up how it's used. It's possible to work around with user-defined conversion operators, but is generally not done.
So, your reasoning about future uses of this mem_fn
does not apply.
You have to specify the exact overload of &A::getAttribute
to use. static_cast
to a fixed type will work (it's a special case where unresolved overloaded functions are permitted):
std::transform(
as.begin(), as.end(), std::back_inserter(ints),
std::mem_fn(static_cast<const int &(A::*)() const>(&A::getAttribute)));