Function as an argument of a constructor of std::function wrapper - c++

I am writing Monitor class for synchronization problem and I would like to implement an 'Entry' class that will wrap a std::function.
I implemented it a bit, used function traits, but right now I am only able to construct Entry objects using prepared std::function object. Attempts to write a constructor that has an plain function as a parameter failed with compiler messages about template argument deduction/substitution and <anonymous> parameter.
The program is working but I am just curious how to implement given constructor, this is my code:
template <class F>
struct FunctionType;
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...)> {
typedef R return_type;
};
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...) const> {
typedef R return_type;
};
template <class F> class Entry {
std::function<F> internalFunction;
...
public:
template <F> Entry(const F& function){
// It doesn't work.
}
template <F> Entry(const std::function<F> function) :
internalFunction(function) {
}
template<F, class... Arguments>
typename FunctionType<F>::return_type operator()(Arguments... arguments){
return internalFunction(arguments...);
}
};

A couple of things:
template<F>
doesn't make any sense at all. You get the type of F from the template parameter on the class, use that and remove this altogether.
Next, it's probably easier for you to use a trailing return type on your operator() function:
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...))
{
return internalFunction(arguments...);
}
(If you have C++14 you can just use auto).
Live Demo
Here's your fixed class
template <class F> class Entry {
std::function<F> internalFunction;
public:
Entry(const F& function){
// It doesn't work.
}
Entry(const std::function<F> function) :
internalFunction(function) {
}
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...)){
return internalFunction(arguments...);
}
};

Related

How can I have a function pointer template as a template parameter?

I am trying to create a class template that expects a type and a function pointer as template parameters. The function pointer is expected to be a member function of the type passed in. I want the user of the class template to be able to pass in a void member function of the type passed in. That member function will then be called on instances of the type passed in every time a certain function of the class template is called. It's a bit hard to explain but it's supposed to work sort of like this:
template<Type, Function> // For the purpose of explaining it
class Foo
{
public:
template<Args... args>
void callOnAll(Args... args)
{
for(Type* ptr : ptrs_)
{
ptr->Function(std::forward<Args>(args)...);
}
}
private:
std::vector<Type*> ptrs_;
}
Assuming that something like this is possible (which I realize it might not be), the key would have to be getting the template parameters for the class right, and getting the update function right. This is what I've come up with but I still can't get it to work:
template<typename T, template<typename... Args> void(T::*func)(Args... args)>
class EngineSystem
{
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
((*handler).*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
The code above does not compile. It points me to the line where I declare the template parameters for the class, underlines void and says expected 'class' or 'typename'.
Is it clear what I'm trying to achieve, and is it possible?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func, but assuming update is called, then (handler->*func)(std::forward<Args>(args)...) still has to be well-formed or compilation will fail.
If you want compilation to fail even if update never gets called, you could use some type traits and a static_assert (or some SFINAE hackery, if you need it) to ensure that func is actually a pointer to a member function of T:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
#include <iostream>
#include <vector>
template <typename T, typename... Args>
class EngineSystem
{
public:
EngineSystem(void(T::*fun)(Args... args)): fun(fun)
{
}
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*fun)(std::forward<Args>(args)...);
}
}
void push(T* t){
handlers_.push_back(t);
}
private:
void(T::*fun)(Args... args);
std::vector<T*> handlers_;
};
struct A {
int x = 3;
void fn(int a, int b){
std::cout << a << b << x;
}
};
template <typename T, typename... Args>
auto makeEngine(void(T::*fun)(Args... args)){
return EngineSystem<T, Args...>(fun);
}
int main() {
EngineSystem<A, int, int> as(&A::fn);
// or deduce types automatically
auto es = makeEngine(&A::fn);
A a;
es.push(&a);
es.update(1,2);
return 0;
}
https://gcc.godbolt.org/z/Pcdf9K9nz

Infer the type of the class owning a member function

Let's consider a kind of "invoke" function (here named "call") that helps to call a member function passed by a template argument.
In this function, I would need to know the type of the class that owns the member function. Is there a way (in c++14 preferably) to do so ?
#include <functional>
template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
// Here we know that f is a member function, so it is of form : &some_class::some_function
// Is there a way here to infer the type some_class from f ? For exemple to instantiate a variable from it :
// imaginary c++ : class_of(f) var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
int main()
{
struct Foo { void bar() {} } foo;
call(&Foo::bar, &foo /*, args*/);
return 0;
}
template <typename>
struct class_of;
template <typename C, typename R, typename... Args>
struct class_of<R(C::*)(Args...)> {
using type = C;
};
Then you can get the type like typename class_of<F>::type. E.g.
template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
typename class_of<F>::type var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
BTW, It depends on your intent, but you can change the template paramters' declaration to get the class type directly.
// I remove the type check because only member function pointer could be passed in
template<typename C, typename R, typename... FArgs, typename... Args>
constexpr decltype(auto) call(R(C::*f)(FArgs...), Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
C var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
songyuanyao beat me to it, but note that you don't need to spell out the function type to deconstruct the member pointer:
template <class MemberPtr>
struct mptr_class;
template <class T, class Class>
struct mptr_class<T Class::*> {
using type = Class;
};
template <class MemberPtr>
using mptr_class_t = typename mptr_class<MemberPtr>::type;

Variadic template parameter order problem

I have a templated function wrapper that I am attempting to update to C++11 syntax (variadic paremeters).
My issue is that I am caught in a "catch 22" where 'Args...' must be the last template parameter, but at the same time, cannot be defined after the function pointer template parameter.
Any idea if this can actually be solved?
template <typename... Args, void(*Function)(Args...)>
class function
{
public:
void operator ()(Args... args) const
{
(*Function)(std::forward<Args...>(args...));
}
};
A possible way is to use the template specialization
template <typename>
struct myFunc;
template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
{
// ...
};
but, this way, you intercept (as template parameter) the type of the function pointer, not the function pointer itself; so you have to pass the function pointer in some way (constructor?).
Also observe that, if you want to use perfect forwarding, you have to transform operator() in a template method receiving arguments as universal references (&&).
Something as follows
template <typename ... As>
R operator() (As && ... args) const
{
return fun(std::forward<As>(args)...);
}
where fun is a pointer of type R(*)(Args...).
The following is a full compiling example
#include <iostream>
#include <utility>
int foo (int, long)
{ return 42; }
template <typename>
struct myFunc;
template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
{
using funPnt = R(*)(Args...);
funPnt fun = nullptr;
myFunc (funPnt f0) : fun{f0}
{ }
template <typename ... As>
R operator() (As && ... args) const
{
return fun(std::forward<As>(args)...);
}
};
int main ()
{
myFunc<decltype(&foo)> mf0{&foo};
std::cout << mf0(1, 2l) << std::endl;
}
If you really want the pointer function as template parameter (but, this way, every function determine a different type; this can be a good or a bad thing according to your needs), you can write the myFunc struct receiving before a type (the same pointer type) and then a value of that type.
So
template <typename T, T>
struct myFunc;
template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<R(*)(Args...), Func>
{
template <typename ... As>
R operator() (As && ... args) const
{
return Func(std::forward<As>(args)...);
}
};
that can be declared
myFunc<decltype(&foo), foo> mf0;
If you can use C++17, you can simplify using auto for type of template values; so you can avoid the type
template <auto>
struct myFunc;
template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<Func>
{
template <typename ... As>
R operator() (As && ... args) const
{
return Func(std::forward<As>(args)...);
}
};
and you can create a myFunc object as follows
myFunc<&foo> mf0;
Addendum: if you can use C++17, you can define a deduction guide for the first example (pointer as member, not as template value parameter)
template <typename R, typename ... Args>
myFunc (R(*)(Args...)) -> myFunc<R(*)(Args...)>;
so, instead of
myFunc<decltype(&foo)> mf0{&foo};
you can simply write
myFunc mf0{&foo};
Off Topic: I hope that you know that you're reinventing the wheel. As suggested by NathanOliver, the standard provide std::function.

Automatic dynamic_cast for arguments in std::function

We have polymorphic classes A and B like:
struct A {
virtual ~A() {}
};
struct B final : public A {
void f() { std::cout << "f" << std::endl; }
};
I want to assign a variable with std::function<void(A*)> from the lambda function with the type of void(B*) without explicitly applying dynamic_cast for the arguments as
std::function<void(A*)> funcA = [](A* a) {
[](B* b) { b->f(); }(dynamic_cast<B*>(a));
};
B b;
funcA(&b);
Are there any ways to automatically achieve this without wrapping the internal function with [](A* a){}?
I set off with the goal of making the following syntax work:
std::function<void(A*)> funcA = dynStdFunc([](B* b) { b->f(); });
To this end, dynStdFunc must:
Detect the parameters of the provided lambda;
Detect the parameters of funcA;
This isn't actually needed on our side, see the update at the end.
Generate a new functor, which glues both parameter lists together via dynamic_cast.
1. Detecting parameters has alrady been the subject of another answer of mine. We can use the following type trait:
// C++17's void_t
template <class...>
using void_t = void;
// Pack of arbitrary types
template <class...>
struct pack { };
namespace detail_parameters {
template <class F, class = void_t<>>
struct parameters { };
template <class F>
struct parameters<F, void_t<decltype(&F::operator ())>>
: parameters<decltype(&F::operator ())> { };
template <class R, class... Params>
struct parameters<R(Params...)> { using type = pack<Params...>; };
// More specializations for functions, function pointers,
// member function pointers...
}
// Retrieve the parameter list from a functionoid
template <class F>
using parameters = typename detail_parameters::parameters<std::remove_reference_t<F>>::type;
This takes in a functionoid type, and returns a pack<T...> containing its parameter types. Great.
2. the parameters required by the std::function aren't known from inside dynStdFunc. The way we make this work is by returning a temporary object, which contains a template for a conversion operator to std::function<Ret(Args...)>.
namespace detail_dynStdFunc {
// F = functionoid, Ps = pack of its parameters
template <class F, class Ps>
struct wrapper;
template <class F, class... Ps>
struct wrapper<F, pack<Ps...>> {
template <class Ret, class... Args>
operator std::function<Ret(Args...)> () {
// Now we know what parameters the `std::function` needs
}
F f;
};
}
template <class F>
auto dynStdFunc(F &&f) {
return detail_dynStdFunc::wrapper<
std::remove_reference_t<F>,
parameters<F>
>{std::forward<F>(f)};
}
3. We've got all we need, generating the new functor is straightforward:
template <class Ret, class... Args>
operator std::function<Ret(Args...)> () {
return [f_ = std::move(f)](Args... args) -> Ret {
return f_(dynamic_cast<Ps>(args)...);
};
}
And that's it! You can see it working live on Coliru.
Update: turns out I've done twice the work I needed to, because std::function can actually instantiate and wrap generic functors directly. Thanks Yakk!
So performing the conversion ourselves is pointless -- let's drop the wrapper:
template <class F, class... Ps>
auto dynStdFunc(F &&f, pack<Ps...>) {
return [f_ = std::forward<F>(f)](auto *... args) -> decltype(auto) {
return f_(dynamic_cast<Ps>(args)...);
};
}
template <class F>
auto dynStdFunc(F &&f) {
return dynStdFunc(std::forward<F>(f), parameters<F>{});
}
See it live on Coliru.

Error when trying to expand template parameter pack

I'm trying to use variadic templates to store the parameter types to a member function. The way I'm trying to achieve this is by associating each type with a key, then storing this key in an std::vector. The code for creating this key is as follows
template <typename T>
class ClassInfo {
public:
inline static void const* GetClassKey() {
static char key;
return &key;
}
};
Then I use the following code to try to store the keys in an std::vector
class WrappedMemberFunction {
void *function_pointer; // Holds the member function pointer
void const* class_type; // Class type key
void const* return_type; // Return type key
std::vector<void const*> parameter_types; // Parameter type keys
void StoreArguments() {}
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArguments<Args...>(); // Error here: No matching member function for call to 'StoreArguments'
}
public:
template <typename Class, typename ReturnType, typename... Args>
WrappedMemberFunction(ReturnType (Class::*member_pointer)(Args...)) {
// Store member pointer as regular old void pointer
function_pointer = (void*&)member_pointer;
// Store class type
class_type = ClassInfo<Class>::GetClassKey();
// Store return type
return_type = ClassInfo<Class>::GetClassKey();
// Store parameter types
StoreArguments<Args...>();
}
};
What I'm getting stuck on is the variadic recursion needed to store each class key. I am getting an error on the line indicated above, which is the recursive step in trying to expand the parameter pack. What am I doing wrong here?
You have:
// function that is not a template
void StoreArguments() {}
// function template that takes N+1 types
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
// call function template that takes N types
StoreArguments<Args...>();
}
Hopefully the comments I added make this clear... you're recursing from a function template taking N+1 types to a function template taking N types. The base case there is a function template taking 0 types. You don't have that, you have a nullary function - which won't be considered.
Your approaches are either to lift your types into values, so your base case actually is a nullary function:
template <class T> struct tag { using type = T; };
void StoreArgumentsImpl() { }
template <typename Arg, typename... Tags>
void StoreArgumentsImpl(tag<Arg>, Tags... tags) {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArgumentsImpl(tags...);
}
template <typename... Args>
void StoreArguments() {
StoreArgumentsImpl(tag<Args>{}...);
}
Or do everything in a single function with the expander trick:
template <typename... Args>
void StoreArguments() {
using expander = int[];
(void)expander{0,
(void(
parameter_types.push_back(ClassInfo<Args>::GetClassKey())
), 0)...
};
}
Or, in C++17 (can't wait), with fold expressions:
template <typename... Args>
void StoreArguments() {
(parameter_types.push_back(ClassInfo<Args>::GetClassKey()), ...);
}
Or, also in C++17, with if constexpr (though this will not work with no arguments):
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Args>::GetClassKey());
if constexpr(sizeof...(Args) > 0) {
StoreArguments<Args...>();
}
}