In c++ 11, how to invoke an arbitrary callable object?
This is exactly what std::invoke
does, but it won't be standard until C++17. You can make your own version, but it can be pretty complicated if it is fully general.
Here's the basic idea for two cases (code taken from cppreference.com):
template <class F, class... Args>
inline auto INVOKE(F&& f, Args&&... args) ->
decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <class Base, class T, class Derived>
inline auto INVOKE(T Base::*pmd, Derived&& ref) ->
decltype(std::forward<Derived>(ref).*pmd) {
return std::forward<Derived>(ref).*pmd;
}
why std::function that store a call to member function can have two different callable type
std::function
stores and can "invoke any CopyConstructible Callable target".
The Callable named requirement is defined as follows:
if f is a pointer to member function of class T:
If std::is_base_of<T, std::remove_reference_t<decltype(t1)>>::value
is true, then INVOKE(f, t1, t2, ..., tN) is equivalent to
(t1.*f)(t2, ..., tN)
Or, in other words: if after removing any reference qualifier on the first parameter the end result is the member function's class (or a subclass), the member function gets invoked for the instance of the class.
otherwise, if t1 does not satisfy the previous items,
then INVOKE(f, t1, t2, ..., tN) is equivalent to
((*t1).*f)(t2, ..., tN).
Otherwise: cross your fingers, hope that the first parameter is a pointer to an instance of the member function's class, and invoke it via the given pointer (hoping against hope that it's a pointer, or something that pretends that it's a pointer).
Final results: either one is equivalent to the other.
Pass callable object by value, assign it to pointer member
Yes this is undefined behavior. After the closing brace of the constructor callable
is destroyed and you have a dangling pointer.
The reason you are not seeing adverse effects is that you really aren't using the instance after it goes out of scope. The function call operator is stateless so it is not trying to access the memory that it no longer owns.
If we add some state to the callable like
class Callable
{
int foo;
public:
Callable (int foo = 20) : foo(foo) {}
void operator()(int x)
{
printf("x = %d\n", x*foo);
}
};
and then we use
int main()
{
UsesTheCallable<Callable>* u = NULL;
{
Callable c(50);
u = new UsesTheCallable<Callable>(c);
}
u->call();
delete u;
return 0;
}
Then you could see this bad behavior. In that run it outputs x = 772773112
which is not correct.
Calling arbitrary function in C++
Basic idea
The basic idea is that you want to encapsulate your functions in some wrapper object which would handle some generic input/output and map them to what your underlying function expects.
First of all let's create a type for storing any value:
// Dummy implementation which only works for some type.
class Value {
long value_;
public:
template<class T>
T get()
{
return (T) value_;
}
template<class T>
Value& operator=(T const& x)
{
value_ = x;
return *this;
}
};
Let's hide our function using generic arguments:
typedef std::function<Value(std::vector<Value>&)> Function;
We now want to wrap any function pointer, in order to conform to this signature. The wrapper function should unwrap the arguments, call the real function and wrap the result in a Value:
template<class F> class FunctionImpl;
template<class R, class... T>
class FunctionImpl<R(*)(T...)>
{
R(*ptr)(T... args);
template<std::size_t... I>
Value call(std::vector<Value>& args, integer_sequence<std::size_t, I...>)
{
Value value;
value = ptr(args[I].get< typename std::tuple_element<I, std::tuple<T...>>::type >()...);
return value;
}
public:
FunctionImpl(R(*ptr)(T... args)) : ptr(ptr) {}
Value operator()(std::vector<Value>& args)
{
constexpr std::size_t count = std::tuple_size<std::tuple<T...>>::value;
if (args.size() != count)
throw std::runtime_error("Bad number of arguments");
return call(args, make_integer_sequence<std::size_t, std::tuple_size<std::tuple<T...>>::value>());
}
};
integer_sequence
and make_integer_sequence
are part of the standard C++17 library but you can write your own implementation.
We now define a type for registering the callable functions:
class Functions {
private:
std::unordered_map<std::string, Function> functions_;
public:
template<class F>
void add(std::string const& name, F f)
{
functions_[name] = FunctionImpl<F>(std::move(f));
}
Value call(std::string name, std::vector<Value>& args)
{
return functions_[name](args);
}
};
And we can use it:
int foo(int x, int y)
{
std::printf("%i %i\n", x, y);
return x + y;
}
int main()
{
Functions functions;
functions.add("foo", &foo);
std::pair<std::string, std::vector<Value>> request = parse_request();
Value value = functions.call(request.first, request.second);
generate_answer(value);
return 0;
}
with the dummy RPC communication functions:
std::pair<std::string, std::vector<Value>> parse_request()
{
std::vector<Value> args(2);
args[1] = 8;
args[0] = 9;
return std::make_pair("foo", std::move(args));
}
void generate_answer(Value& value)
{
std::printf("%i\n", value.get<int>());
}
We get:
8 9
17
Of course, this is highly simplified and you'll face many issues if you want to generalize it:
you might want to propagate exceptions as well;
integer types (eg.
long
) do not have the same size on different platforms;it starts gettings complicated if you want to handle pointers and references (you should probably not);
you'll have to add code for serialization/deserialization of all the types you're using.
Serialization
On way to handle the serialization, would be to use generic programming for serialization/deserialization:
template<class T> class Type {};
typedef std::vector<char> Buffer;
// I'm clearly not claiming this would be efficient, but it gives
// the idea. In pratice, you might want to consume some streaming I/O
// API.
class Value {
Buffer buffer_;
public:
template<class T>
T get()
{
return deserialize(Type<T>(), buffer_);
}
template<class T>
Value& operator=(T const& x)
{
serialize(x, buffer_);
return *this;
}
};
inline std::uint32_t deserialize(Type<std::uint32_t>, Buffer const& buffer)
{
if (buffer.size() != sizeof(std::uint32_t))
throw std::runtime_error("Could not deserialize uint32");
std::uint32_t res;
memcpy(&res, buffer.data(), sizeof(std::uint32_t));
return be32toh(res);
}
inline void serialize(std::uint32_t value, Buffer const& buffer)
{
buffer.resize(sizeof(std::uint32_t));
value = htobe32(value);
memcpy(buffer.data(), &value, sizeof(std::uint32_t));
}
Another possibility is to use generic programming and let the Function
do the serialization/deserialization.
What is the best type for a callable object in a template method?
In general, I do not like passing callable
objects by const reference, because it is not that flexible (e.g. it cannot be used on mutable lambdas). I suggest to pass them by value. If you check the stl algorithms implementation, (e.g. for std::for_each
), all of the callable objects are passed by value as well.
Doing this, the users are still able to use std::ref(func)
or std::cref(func)
to avoid unnecessary copying of the callable object (using reference_wrapper
), if desired.
Are pointer to member functions not callable object
What i am asking is that whether pointer to member function are callable object according to the standard.
Yes, a pointer to a member function is a callable object according to the standard.
From func.def#4:
A callable object is an object of a callable type.
And from func.def#3:
A callable type is a function object type ([function.objects]) or a pointer to member.
Thus, the highlighted part of the quoted statement that says "a pointer to member is not a callable object" from C++ Primer is incorrect according the standard.
Inferring the call signature of a lambda or arbitrary callable for make_function
I've come up with a fairly nasty non-library solution, using the fact that lambdas have operator()
:
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename T>
struct get_signature_impl { using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type; };
template<typename R, typename... A>
struct get_signature_impl<R(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(&)(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(*)(A...)> { using type = R(A...); };
template<typename T> using get_signature = typename get_signature_impl<T>::type;
template<typename F> using make_function_type = std::function<get_signature<F>>;
template<typename F> make_function_type<F> make_function(F &&f) {
return make_function_type<F>(std::forward<F>(f)); }
Any ideas where this can be simplified or improved? Any obvious bugs?
Purpose of perfect forwarding for Callable argument in invocation expression?
For the same purpose as for arguments: so when Func::operator()
is a ref-qualified:
struct Functor
{
void operator ()() const & { std::cout << "lvalue functor\n"; }
void operator ()() const && { std::cout << "rvalue functor\n"; }
};
Demo
Accept any kind of callable and also know argument type
Here's an example that will work for most callables including functors and lambdas (although not for generic functors as @Yakk demonstrated in a comment on the question).
The code can also be useful when determining return type and multiple arguments.
template <typename T>
struct func_traits : public func_traits<decltype(&T::operator())> {};
template <typename C, typename Ret, typename... Args>
struct func_traits<Ret(C::*)(Args...) const> {
using result_type = Ret;
template <std::size_t i>
struct arg {
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename T>
void option(T&& t) {
using traits = func_traits<typename std::decay<T>::type>;
using return_t = typename traits::result_type; // Return type.
using arg0_t = typename traits::template arg<0>::type; // First arg type.
// Output types.
std::cout << "Return type: " << typeid(return_t).name() << std::endl;
std::cout << "Argument type: " << typeid(arg0_t).name() << std::endl;
}
To add support for regular functions add a specialization e.g.
template <typename Ret, typename... Args>
struct func_traits<Ret(*)(Args...)> { /* ... */ }
More useful info: Is it possible to figure out the parameter type and return type of a lambda?
Related Topics
Narrowing Conversion from Unsigned to Double
Calculating the Info-Hash of a Torrent File
Reading JSON File with C++ and Boost
Referencing Memory Operands in .Intel_Syntax Gnu C Inline Assembly
Want to Efficiently Overcome Mismatch Between Key Types in a Map in Boost.Interprocess Shared Memory
Undefined Reference to a Static Member of the Class
Vscode G++ It Isn't Finding .Cpp Definition Files
Deleted Function in Std::Pair When Using a Unique_Ptr Inside a Map
In C++ 11, How to Invoke an Arbitrary Callable Object
Why Can't I Replace Std::Map with Std::Unordered_Map
Gcc Can Compile a Variadic Template While Clang Cannot
Memory Allocation and Deallocation Across Dll Boundaries
C++ Double Dispatch for Equals()
Convert Integer to Binary and Store It in an Integer Array of Specified Size:C++
Unique_Ptr and Openssl's Stack_Of(X509)*