How can I have a function pointer template as a template parameter? - c++

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

Related

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.

Check if a function template is unary

I am trying to check if a function argument passed is unary or not, something like so
template <typename Func>
using EnableIfUnary = std::enable_if_t<std::is_same<
decltype(std::declval<Func>()(std::declval<const int&>())),
decltype(std::declval<Func>()(std::declval<const int&>()))>::value>;
template <typename Func, EnableIfUnary<Func>* = nullptr>
void do_something(Func func) { ... }
// and use like so
template <typename Type>
void foo(Type) { cout << "foo(Type)" << endl; }
template <typename Type>
void bar(Type) { typename Type::something{}; }
int main() {
do_something(foo);
return 0;
}
Is there a better way to check if a function is unary? My current approach doesn't work when the function pass in (foo() in my example) uses the type in a way that would not work with ints.
In the above case foo is legal and bar isn't, since there is no type named something in int (which is what the enable if checks for)
template<typename...>
struct is_unary_function : std::false_type {};
template<typename T, typename R>
struct is_unary_function<R(*)(T)> : std::true_type {};
Live Demo

Function template taking a template non-type template parameter

How does one take a templated pointer to a member function?
By templated I mean that the following types are not known in advance:
template param T is class of the pointer to member
template param R is the return type
variadic template param Args... are the parameters
Non-working code to illustrate the issue:
template <???>
void pmf_tparam() {}
// this works, but it's a function parameter, not a template parameter
template <class T, typename R, typename... Args>
void pmf_param(R (T::*pmf)(Args...)) {}
struct A {
void f(int) {}
};
int main() {
pmf_tparam<&A::f>(); // What I'm looking for
pmf_param(&A::f); // This works but that's not what I'm looking for
return 0;
}
Is it possible to achieve the desired behavior in C++11?
I don't think this notation is possible, yet. There is proposal P0127R1 to make this notation possible. The template would be declared something like this:
template <auto P> void pmf_tparam();
// ...
pmf_tparam<&S::member>();
pmf_tparam<&f>();
The proposal to add auto for non-type type parameters was voted into the C++ working paper in Oulu and the result was voted to become the CD leading towards C++17 also in Oulu. Without the auto type for the non-type parameter, you'd need to provide the type of the pointer:
template <typename T, T P> void pmf_tparam();
// ...
pmf_tparam<decltype(&S::member), &S::member>();
pmf_tparam<decltype(&f), &f>();
As you've not said really what you are after in the function, the simplest is:
struct A {
void bar() {
}
};
template <typename T>
void foo() {
// Here T is void (A::*)()
}
int main(void) {
foo<decltype(&A::bar)>();
}
However if you want the signature broken down, I'm not sure there is a way to resolve the types directly, however you can with a little indirection...
struct A {
void bar() {
std::cout << "Call A" << std::endl;
}
};
template <typename R, typename C, typename... Args>
struct composer {
using return_type = R;
using class_type = C;
using args_seq = std::tuple<Args...>;
using pf = R (C::*)(Args...);
};
template <typename C, typename C::pf M>
struct foo {
static_assert(std::is_same<C, composer<void, A>>::value, "not fp");
typename C::return_type call(typename C::class_type& inst) {
return (inst.*M)();
}
template <typename... Args>
typename C::return_type call(typename C::class_type& inst, Args&&... args) {
return (inst.*M)(std::forward<Args...>(args...));
}
};
template <class T, typename R, typename... Args>
constexpr auto compute(R (T::*pmf)(Args...)) {
return composer<R, T, Args...>{};
}
int main() {
foo<decltype(compute(&A::bar)), &A::bar> f;
A a;
f.call(a);
}
The above should do what you are after...
What you can do is
template <template T, T value>
void pmf_tparam() {}
and then
pmf_tparam<decltype(&A::f), &A::f>();
The problem is not knowing the type of the argument and wanting a template argument of that type.
With an additional decltype (still in the templated parameter), this works:
#include <iostream>
using namespace std;
template <typename T, T ptr>
void foo (){
ptr();
}
void noop() {
cout << "Hello" << endl;
}
int main() {
//Here have to use decltype first
foo<decltype(&noop), noop>();
return 0;
}

Function as an argument of a constructor of std::function wrapper

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...);
}
};

Is it possible to place function pointer in template parameter ahead of dependent type?

I have a template that has a function pointer as it's 2nd parameter and a type that the function pointer is dependent on as it's first.
i.e.
template <typename P, typename void(*fn)(P)>
auto function(P) -> otherType<P, fn>;
I want to make it so that I can just specify the function pointer in the template list without having to specify the dependent type as that type should somehow be able to be inferred from the function pointer that I specify (or maybe even the parameter list, but I think that it probably is too far down the line).
My first thought was to defer the conversion to a template parameter value, by passing a template typename and then convert to a value after the fact though template metaprogramming wizardry.
i.e.
template <typename F, typename P>
auto function(P) -> [[ something here to get otherType<P, fn> if F was a function pointer ]]
However, I'm not sure how I can do this. Any ideas?
Edit
What I'm trying to accomplish here is to make a helper function that will generate a class object. So, given what was said by StenSoft, this is what I've come up with. Unfortunately it doesn't work with a failure inside the main() function where it cannot match to the correct function due to deduction failure:
#include <iostream>
#include <functional>
template<typename T, typename F>
struct wrapper_fntor
{
T m_t;
F m_f;
wrapper_fntor(T t, F f) : m_t(t), m_f(f) {}
void invoke() { m_f(m_t); }
};
template<typename T, void(*fn)(T)>
struct wrapper_fn
{
T m_t;
wrapper_fn(T t) : m_t(t) {}
void invoke() { fn(m_t); }
};
template <typename T>
struct Wrapper;
template <typename Ret, typename P>
struct Wrapper<Ret(P)>
{
template <Ret(*fn)(P)>
static Ret function(P p)
{
return fn(std::forward<P>(p));
}
template <Ret(*fn)(P)>
static P get_param_type(P);
typedef decltype(get_param_type<Ret(P)>()) param_t;
};
template<typename F>
wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function> make_wrapper(typename Wrapper<F>::param_t param)
{
return wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function>(param);
}
template<typename F>
wrapper_fntor<typename Wrapper<F>::param_t, F> make_wrapper(typename Wrapper<F>::param_t param, F fntor)
{
return wrapper_fntor<typename Wrapper<F>::param_t, F>(param, fntor);
}
void function(int value)
{
std::cout << "function called " << value << std::endl;
}
int main()
{
auto x = make_wrapper<function>(3);
x.invoke();
}
demo
For a similar problem I have used a templated function inside a templated wrapper class and a macro (this actually works with any parameters and return type):
template <typename T>
struct Wrapper;
template <typename Ret, typename... Params>
struct Wrapper<Ret(Params...)>
{
template <Ret(*fn)(Params...)>
static Ret function(Params... params)
{
return fn(std::forward<Params>(params)...);
}
};
#define FUNCTION(fn) \
Wrapper<decltype(fn)>::function<fn>