Why does INVOKE always dereference data members instead of calling when possible? - c++

This question (Why does INVOKE facility in the C++11 standard refer to data members?) asks why INVOKE discusses data members but ignores how they are actually invoked.
This question (What is std::invoke in c++?) discusses why they are accessed, but why they are not called if callable.
[func.require]:
Define INVOKE(f, t1, t2, …, tN) as follows:
(1.1) (t1.*f)(t2, …, tN) when f is a pointer to a member function of a class T and is_­base_­of_­v<T, remove_­reference_­t<decltype(t1)>> is true;
(1.2) (t1.get().*f)(t2, …, tN) when f is a pointer to a member function of a class T and remove_­cvref_­t<decltype(t1)> is a specialization of reference_­wrapper;
(1.3) ((*t1).*f)(t2, …, tN) when f is a pointer to a member function of a class T and t1 does not satisfy the previous two items;
(1.4) t1.*f when N == 1 and f is a pointer to data member of a class T and is_­base_­of_­v<T, remove_­reference_­t<decltype(t1)>> is true;
(1.5) t1.get().*f when N == 1 and f is a pointer to data member of a class T and remove_­cvref_­t<decltype(t1)> is a specialization of reference_­wrapper;
(1.6) (*t1).*f when N == 1 and f is a pointer to data member of a class T and t1 does not satisfy the previous two items;
(1.7) f(t1, t2, …, tN) in all other cases.
1.4 through 1.6 deal with access to pointers to data members, which makes sense given functors and stored callables. What I don't understand is why it doesn't call those members, but instead simply dereferences them? I would expect that 1.4 would parallel the syntax of 1.1 and er...invoke the object in question if f possesses an operator ().
Why is this restriction in place, and what purpose does it serve?
Here's some code for clarification:
#include <functional>
#include <iostream>
struct func1
{
void operator()() { std::cout << "Invoked functor\n"; }
};
void func2()
{
std::cout << "Invoked free function\n";
}
struct D1 {};
struct T1 {
func1 f1;
void func3() { std::cout << "Invoked member function\n"; }
D1 d1;
};
int main()
{
T1 t1;
func1 free_f1;
std::invoke(&T1::f1, t1); //does nothing
std::invoke(&func1::operator(), t1.f1); //okay, so there is a workaround, if clumsy
std::invoke(&func2); //calls func2
std::invoke(&T1::func3, t1); //calls func3
std::invoke(&T1::d1, t1); //does nothing (expected)
std::invoke(free_f1); //works on non-member functors
return 0;
}
This compiles nicely, but only calls func1() on the second call to invoke. I understand why INVOKE does nothing but dereference the first argument when it is not a callable object. My question is why does the standard not allow for calling callable pointers to data members, i.e. why does the Standard not mandate that f1 is called in the first usage of std::invoke above?
Edit: since std::invoke was added in C++17, I'm tagging this question as such hoping someone involved in the process can shed some light.
Here's the original paper for adding std::invoke(), which actually explains in its motivation that it wants to handle functors uniformly:
Although the behaviour of the INVOKE expression may be reproduced by combination of the existing standard library components, separate treatment of the functors and member pointers is required in such solutions.
In the code above, you can see this works...just not for pointers to member data that are functors themselves. Is this simply an oversight?

When C++11's standard library was being assembled, it took on a number of features from a variety of Boost libraries. For the purpose of this conversation, the following Boost tools matter:
bind
function
reference_wrapper
mem_fn
These all relate to, on one level or another, a callable thing which can take some number of arguments of some types and results in a particular return value. As such, they all try to treat callable things in a consistent way. C++11, when it adopted these tools, invented the concept of INVOKE in accord with perfect forwarding rules, so that all of these would be able to refer to a consistent way of handling things.
mem_fn's sole purpose is to take a pointer to a member and convert it into a thing directly callable with (). For pointers to member functions, the obvious thing to do is to call the member function being pointed at, given the object and any parameters to that function. For pointers to member variables, the most obvious thing to do is to return the value of that member variable, given the object to access.
The ability to turn a data member pointer into a unary functor that returns the variable itself is quite useful. You can use something like std::transform, passing it mem_fn of a data member pointer to generate a sequence of values that accesses a specific accessible data member. The range features added to C++20 will make this even more useful, as you can create transformed ranges, manipulating sequences of subobjects just by getting a member pointer.
But here's the thing: you want this to work regardless of the type of that member subobject. If that subobject just so happens to be invokable, mem_fn ought to be able to access the invokable object as though it were any other object. The fact that it happens to be invokable is irrelevant to mem_fn's purpose.
But boost::function and boost::bind can take member pointers. They all based their member pointer behavior on that of boost::mem_fn. Therefore, if mem_fn treats a pointer to a data member as a unary functor returning the value of that member, then all of these must treat a pointer to a data member that way.
So when C++11 codified all of these into one unifying concept, it codified that practice directly into INVOKE.
So from an etymological perspective, that is why INVOKE works this way: because all of these are meant to treat callables identically, and the whole point of mem_fn with regard to data member pointers is to treat them as unary functions that return their values. So that's how everyone else has to treat them too.
And isn't that a good thing? Is that not the correct behavior? Would you really want to have pointers to data members behave wildly differently if the type the member pointer points to happens to be callable than if it doesn't? That would make it impossible to write generic code that takes data member pointers, then operates on some sequence of objects. How would you be able to generically access a data member pointer, if you weren't sure it would get the subobject being reference or invoke the subobject itself?

Related

Should std::invoke work when the first input is an lvalue reference to a member function pointer?

While trying to implement something similar to std::invoke, I noticed the following subtlety in the standard. I'm curious if anybody can give me a language lawyer explanation that helps decide whether libc++'s implementation is correct.
In N4868 (basically C++20), [func.invoke] defines std::invoke this way:
template<class F, class... Args>
constexpr invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
noexcept(is_nothrow_invocable_v<F, Args...>);
Returns: INVOKE(std​::​forward<F>(f), std​::​forward<Args>(args)...).
In turn, [func.require]/1 defines INVOKE as follows:
Define INVOKE(f, t_1, t_2, ..., t_N) as follows:
[...] when f is a pointer to a member function of a class T and [...]
[...] when f is a pointer to a member function of a class T and [...]
[...] when f is a pointer to a member function of a class T and [...]
[...] when N == 1 and f is a pointer to a data member of a class T and [...]
[...] when N == 1 and f is a pointer to a data member of a class T and [...]
f(t_1, t_2, ..., t_N) in all other cases.
My question is what should happen with the following snippet:
struct Callable {
int DoSomething() { return 17; }
};
int (Callable::*member_fn_ptr)() = &Callable::DoSomething;
assert(17 == std::invoke(member_fn_ptr, Callable{}));
This works under libc++, but in my implementation it causes a compilation error. That's because my implementation falls through to the "in all other cases" clause above, attempting to call the member function pointer as if it were a plain function pointer.
I thought this was a bug in my implementation until I read the standard a little more closely. The definition of std::invoke uses a forwarding reference for f, and clearly says it should be forwarded. In this case that means that it will be forwarded as an lvalue reference. Then in the cascade of logic in the definition of INVOKE, it seems like this should match the final case: f is not a pointer to a member function, but rather a reference to a pointer to a member function. And libc++'s implementation of <type_traits> agrees with me:
static_assert(!std::is_member_function_pointer_v<decltype(member_fn_ptr)&>)
In libc++ this works out only because the SFINAE for the first case of INVOKE checks whether std::decay_t<decltype(f)> is a member function pointer, not decltype(f).
Is this a bug in libc++, a bug in the standard, or a bug in my understanding of the standard?

Is there a reason we cannot name a non-static member function in an unevaluated context?

When reading [expr.prim.id], one will see that
An id-expression that denotes a non-static data member or non-static
member function of a class can only be used:
if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
The fact that the bullet above applies only to data members is unclear to me. Intuitively I'd expect the following to be well formed:
#include <type_traits>
using func = int();
class bar {
func foo; // This is valid, and not the subject of the question
};
static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!");
But the decltype() is ill-formed even before the static assertion is checked.
Is there some ambiguity I'm missing?
Is there some ambiguity I'm missing?
The fact there's a whole lot of type information that is added as part of that member function declaration.
While func may certainly be used to declare that member, the story doesn't end here. Once the member is declared, it's type is completed. That involves adding a couple of other things, like cv-qualifers and ref-qualifiers. In the case of foo, all the default implicit ones are determined, and they become part of bar::foo's type. As specified by [dcl.fct]/8:
The return type, the parameter-type-list, the ref-qualifier, the
cv-qualifier-seq, and the exception specification, but not the default
arguments, are part of the function type.
There's no way to specify them explicitly in the above declaration of foo (though they may be added to func), but they may be added in general:
class bar {
int foo() const volatile &&;
};
They are part of the function type, and decltype(bar::foo) should address them if they appear (and if I gather correctly, even if they don't).
Where does the const volatile && go when we attempt to evaluate decltype(bar::foo)?
Should it be ignored? That can be done. But losing type information is rarely a good thing.
Should we retain it, and the type decltype evaluates to be a pointer to a member function, instead?
That too would work, but now it's different from how data members would behave when named in an unevaluated context. We introduce a discrepancy.
Should it be retained, and the type resolved to something else? Perhaps something like int(foo const volatile&&) or int() const volatile && (another form of function type)? That breaks the symmetry one would expect to have, and is again a discrepancy to data members.
There is no easy or obvious way in which allowing it would always work well. So rather than complicate matters for a feature that would see limited use, it's better to regard it as ill-formed.
Is there some ambiguity I'm missing?
I don't think so. It's probably more that there was a definite need to evaluate non-static data members and not so much for non-static member functions.
However, this:
static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!");
doesn't make much sense. The type of &bar::foo is not func*, it's func bar::*. And there isn't a way to spell that without a pointer, so having to be able to evaluate decltype(bar::foo) means introducing whole new type syntax? Doesn't seem worth it.
Note that decltype(bar::foo) cannot be func because func is a function type, but bar::foo is a member function.
I don't see any reason.
Look at this:
typedef void Func();
Func freeFunction;
struct Foo {
Func memberFunction;
};
freeFunction's declaration is Func freeFunction;. So, decltype(freeFunction) is void(), i.e. Func.
Using the same logic, As Foo::memberFunction is declared as Func too, I'd expect decltype(Foo::memberFunction) to be Func too. But that's not the case, as this doesn't compile.
Just like a int a; decltype(a) resolves to int, even if int a; is a member, decltype(Foo::memberFunction) should be OK.
Note, that qualifiers can be handled too, there is nothing special about them (of course, in this case, Func can only be used for declaring non-static member functions):
typedef void Func() const volatile &&;
struct Foo {
Func memberFunction;
};
Here, I'd expect that decltype(Foo::memberFunction) to be void() const volatile &&, so I can copy its declaration:
struct Bar {
decltype(Foo::memberFunction) myMemFn;
};
Quote from the C++14 standard (9.2/11):
[ Note: The type of a non-static member function is an ordinary
function type, and the type of a non-static data member is an ordinary
object type. There are no special member function types or data member
types. — end note ]
This quote means that it would be sensible, if decltype(<member_function>) returned a type of ordinary function.

Why use mem_fn?

I'm confused as to why std::mem_fn is needed.
I have a function that takes in any callable (lambda, function pointer, etc),and binds it to an argument.
Eg:
template<class T>
void Class::DoBinding(T callable) {
m_callable = std::bind(callable, _1, 4);
}
//somewhere else
Item item;
m_callable(item);
All code samples I've seen do:
//some defined member function
Item::Foo(int n);
DoBinding(std::mem_fn(&Item::Foo));
Why can't it simply be:
DoBinding(&Item::Foo);
It seems the latter is callable without having to use std::mem_fn, so why is it needed?
This is because generic code that expects UnaryFunction or BinaryFunction will invoke it directly with the regular call syntax. So to pick an arbitrary algorithm like for_each, it could well be implemented like:
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
for (; first != last; ++first) {
f(*first); // <== N.B. f(*first)
}
return f;
}
If you called for_each() with &Item::Foo, the code try to call (&Item::Foo)(x), which is ill-formed since for pointers to members you have to write (x.*&Item::Foo)(). It's that syntactical difference that mem_fn is meant to solve: mem_fn deals with the invocation syntax of pointers to members so that you can use all the algorithms with pointers to members as well as functions and function objects. You cannot have for_each(v.begin(), v.end(), &Item::Foo) but you can have for_each(v.begin(), v.end(), mem_fn(&Item::Foo)).
This works just fine in std::bind() (and std::thread and std::function and ...) natively since those all have explicit handling for pointers to members separately. And since DoBinding() itself calls std::bind(), there is no reason for std::mem_fn in this case.
There is was a proposal to get rid of this syntactic difference: P0312. It did not go well.
This is usually done because the person who writes DoBinding(std::mem_fn(&Item::Foo)) has no idea that DoBinding can take a member pointer directly.
Remember: std::sort(..., &Item::Foo) will fail, because sort expects the value to be a directly-callable function object. And member pointers are not. Indeed, pretty much every algorithm in the C++ standard library will fail when given a member pointer instead of a directly-callable type. Your DoBinding only works because you're using std::bind, which has a special overload for member pointers. The caller of DoBinding doesn't necessarily know you're doing that.
Most code that takes callables by template parameters will choke on a member pointer. So to be safe, we don't pass member pointers around as objects that can be directly called; use mem_fn to turn it into such an object.

Points to member variables and templating

I am currently using a templated function to evaluate the derivatives of mathematical functions, like so
template <class func_type>
arma::mat matrixDerivative
(func_type func, const double x, double h, double b=1.4) {
// <implementation details>
}
The template parameter allows me to use either function pointers or functors to evaluate the right-hand side.
Is there an easy way to extend this to evaluate the derivatives of functions that are class methods? I wasn't able to wrap my head around the use of function pointers to member functions and I couldn't work out the details of having a functor as a class attribute that still had access to its parent's attributes and methods.
My questions usually aren't clear, so feel free to ask for clarifications in the comments before answering.
In C++11 simply use a lambda:
[&]( double x )->double {
return ptr->method(x);
}
which generates a function object that can be invoked with double. The above construct assumes that the lambda will be used and discarded before the end of the current scope ([&] is unsafe otherwise).
Note that ->double can be omitted for single-line and void returning lambdas in C++11, and omitted even on multi-line lambdas in C++1y if you are ok with the return type it deduces (based off the first return statement in your function).
In C++03, std::mem_fun can be used, or you can create a custom function object.
In C++1y:
[&](auto&&... x) {
return ptr->method(std::forward<decltype(x)>(x)...);/
}
creates a perfect-forwarding functor wrapper. I would rarely do that kind of thing, even in C++1y, outside of seriously industrial library code. Less verbose we get:
[&](auto&&... x) {
return ptr->method(x...);
}
which lets us imperfectly forward, and defer selection of the overload to the point of use of the lambda, not the point where the lambda was written, which can be nice. (if any of the methods use rvalue or by-value calls, going back to perfect forwarding becomes tempting)
In C++11, std::mem_fn requires that the method in question not be overloaded, or that the overload be manually resolved (with an arcane-looking cast). std::bind then wraps that with a perfect-forwarding function object. The main advantage this procedure is is that the type of the construct, while implementation defined, can be determined, so you can have a function that returns the type in question. However, that is a pretty esoteric advantage: I would go with the lambda.
Lambdas, while strange, are increasingly common in C++, and are easier to understand what they are doing than a chain bind mem_fun expression in my experience as they look more like "normal" code (after you get over the "magic").

Difference between std::function<> and a standard function pointer? [duplicate]

This question already has answers here:
Should I use std::function or a function pointer in C++?
(6 answers)
Closed 5 years ago.
Whats the difference between std::function<> and a standard function pointer?
that is:
typedef std::function<int(int)> FUNCTION;
typedef int (*fn)(int);
Are they effectively the same thing?
A function pointer is the address of an actual function defined in C++. An std::function is a wrapper that can hold any type of callable object (objects that can be used like functions).
struct FooFunctor
{
void operator()(int i) {
std::cout << i;
}
};
// Since `FooFunctor` defines `operator()`, it can be used as a function
FooFunctor func;
std::function<void (int)> f(func);
Here, std::function allows you to abstract away exactly what kind of callable object it is you are dealing with — you don't know it's FooFunctor, you just know that it returns void and has one int parameter.
A real-world example where this abstraction is useful is when you are using C++ together with another scripting language. You might want to design an interface that can deal with both functions defined in C++, as well as functions defined in the scripting language, in a generic way.
Edit: Binding
Alongside std::function, you will also find std::bind. These two are very powerful tools when used together.
void func(int a, int b) {
// Do something important
}
// Consider the case when you want one of the parameters of `func` to be fixed
// You can used `std::bind` to set a fixed value for a parameter; `bind` will
// return a function-like object that you can place inside of `std::function`.
std::function<void (int)> f = std::bind(func, _1, 5);
In that example, the function object returned by bind takes the first parameter, _1, and passes it to func as the a parameter, and sets b to be the constant 5.
They are not the same at all. std::function is a complex, heavy, stateful, near-magic type that can hold any sort of callable entity, while a function pointer is really just a simple pointer. If you can get away with it, you should prefer either naked function pointers or auto-bind/auto-lambda types. Only use std::function if you really need a systematic way of organizing a heterogeneous collection of callable entities, such as functions, functors, capturing lambdas and bind expressions.
Update: A bit of explanation about auto types: Compare the following two functions:
void do_something_1(std::function<void(int)> f, int a) { f(a); }
template <typename F, typename A> void do_something_2(F f, A a) { f(a); }
Now imagine invoking them with a lambda or a bind expression:
do_something_X([foo, &bar](int n){ bar += n*foo; }, 12);
do_something_X(std::bind(X::bob, &jim, true, _1, Blue), 13);
The second version with the template is more efficient, because in both cases, the argument F is deduced to the actual, unknowable type of the expression. The first version, with std::function, isn't a template and may look simpler and more deliberate, but it always forces the construction of the std::function object, and quite possibly carries multiple type erasure and virtual dispatch costs.
A std::function has state. It can hold additional parameters "bound" into it.
These parameters can range from things like other classes, other functions, or even this pointers for member function calls.
The replacement function pointer is not typedef int (*fn)(int);
It is typedef int (*fn)(void*,int);, with the void* reperensting the state that would be hidden in the std::function.
No.
One is a function pointer; the other is an object that serves as a wrapper around a function pointer.
They pretty much represent the same thing, but std::function is far more powerful, allowing you to do make bindings and whatnot.