std::function like delegate template class - c++

Hi I am trying to write a delegate class that can take a template argument similar to a standard function signature and create a delegate for a member function pointer as shown below in the main. The code may be oversimplified but that is what I was looking for was a simple and fast solution to this problem with as little overhead as possible. I think this implementation is pretty close to achieving what I want if I can get the type T in the class without runtime polymorphism etc.
template<class T>
struct FastDelegate {};
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...)) : m_t(t), m_f(f) {}
R operator()(Args... p)
{
return (m_t->*m_f)(std::forward<Args>(p)...);
}
T* m_t; // How can I capture T as a type in this partial specialization?
R (T::*m_f)(Args...);
};
struct Test
{
int add ( int x, int y ) { return x+y; }
};
int main ()
{
int x = 5;
int y = 4;
Tester t;
FastDelegate<int (int,int)> d (&t, &Test::calc );
int z = d(x,y);
}

You could capture the objects as a void*, store the member function in random member function type, and have a function restore the necessary types. This approach avoid allocating any memory on the heap. The problematic step is the conversion from a member function of some type to another member function. However, according to 5.2.10 [expr.reinterpret.cast] paragraph 10 this approach can be used safely as long at the member function is cast back to its original type before being used:
[...] The result of this conversion is unspecified, except in the following cases:
converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.
Below is an example which implements this approach. Note, however, that it is probably easier to use std::function<R(Args...)> with a suitable lambda as the standard library is likely to implementation an approach like that in the first place.
#include <iostream>
#include <utility>
template<class T>
struct FastDelegate {};
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
struct dummy {};
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...))
: m_t(t)
, m_f(reinterpret_cast<void (dummy::*)()>(f))
, m_call([](void(dummy::*d)(), void* v, Args... a){
typedef R (T::*mem)(Args...);
T* t = static_cast<T*>(v);
mem f = reinterpret_cast<mem>(d);
return (t->*f)(std::forward<Args>(a)...);
}) {
}
R operator()(Args... p) {
return (this->m_call)(this->m_f, this->m_t, std::forward<Args>(p)...);
}
void* m_t;
void (dummy::*m_f)();
R (*m_call)(void (dummy::*)(), void*, Args...);
};
struct Tester
{
int add ( int x, int y ) {
std::cout << "add(" << x << ", " << y << ")\n";
return x+y;
}
};
int main ()
{
int x = 5;
int y = 4;
Tester t;
FastDelegate<int (int,int)> d (&t, &Tester::add);
int z = d(x,y);
}

You don't need to capture type T, because you can use t->*m_f as a function<R(Args...)>
template<class R, class... Args>
struct FastDelegate<R (Args...)>
{
template <typename T>
FastDelegate(T* t, R (T::*f)(Args...))
: m_f([=](Args... v){ return (t->*f)(std::forward(v)...); }) {}
R operator()(Args... p)
{
return m_f(std::forward<Args>(p)...);
}
std::function<R(Args...)> m_f;
};
If you want to compare 2 FastDelegate instance by comparing t and f, there is still no need for type info, just take raw pointer.

Related

How to determine the return type of a function in template

I am trying to write a class similar to std::function, just to learn how it works but I am having problem determining the return type of the function.
I found this from one of the answers here on stack overflow. I am trying to do something similar but It does not work and I do not know why.
template< class Fx >
class function
{
public:
function() = default;
function(Fx* fx)
{
this->fx = fx;
}
template < class... A >
ReturnType operator()(A... args)
{
//return ((*fx)(args), ...); ??
}
private:
template<class F>
struct return_type;
template< class R, class... A>
struct return_type<R(*)(A...)>
{
using type = R;
};
using ReturnType = return_type<Fx>::type;
Fx* fx;
};
int sum(int a, int b) { return a + b; };
int main()
{
function<int(int, int)> mysum{ sum };
mysum(10, 10);
}
It gives me an error on line
using ReturnType = return_type<Fx>::type;
saying incomplete type is not allowed. Why does it not pick the specialized one?
Since Fx is supposed to be a function type, not a function pointer type, so the specialization should be declared as:
template< class R, class... A>
struct return_type<R(A...)>
{
using type = R;
};
Other issues:
Change using ReturnType = return_type<Fx>::type; to using ReturnType = typename return_type<Fx>::type;.
Move the declaration of ReturnType (and definition of return_type) before using it as the return type of operator().
Change return ((*fx)(args), ...); to return (*fx)(args...); in the operator(); i.e. all the arguments are supposed to be passed to fx instead of calling fx multiple times with each argument.
LIVE
BTW: Return type deduction (since C++14) is worthy of consideration too. E.g.
template < class... A >
auto operator()(A... args)
{
return (*fx)(args...);
}
LIVE
You should change your template in the class instantiation:
template <typename R, typename ...Args>
class function {
...
R operator()(Args... args){
return fx(...args)
}
}

Passing Template Variable to Template Function in C++14

I'm writing a compiler that compiles to C++ and am having type issues with my C++ code. The language is meant to be lazy, so we have a lazy value wrapper, Chunk. Here is a part of it, along with the problematic code:
#include <functional>
#include <memory>
template<class T>
class Chunk
{
public:
Chunk();
Chunk(std::function<T()> f);
T operator()();
std::function<T()> f_;
private:
std::shared_ptr<T> cache_;
};
template<class T>
T Chunk<T>::operator()()
{
if(cache_ == nullptr)
cache_ = std::make_shared<T>(f_());
return *cache_;
}
template<class T, class F>
T operator*(Chunk<T> t1, Chunk<F> t2)
{
return t1() * t2();
}
template<class T, class... Args>
T apply(Chunk<std::function<T(Args...)>> c, Args... as)
{
return c()(as...);
}
template<class F>
auto toChunk(F f) -> Chunk<decltype(f())>
{
return Chunk<decltype(f())>(f);
}
template<class T, class F>
struct ops
{
static const auto multiply =
toChunk([]() { return ops::multiply_; });
static const auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
};
int main()
{
Chunk<double> t = toChunk([]() { return 1.0; });
Chunk<float> f = toChunk([]() { return 2.0f; });
apply(ops::multiply, t, f);
return 0;
}
I can't figure out a definition of multiply to make this work without getting a used without template parameters error. (There may be a second issue here because multiply_ isn't a std::function, but the compiler breaks on the lack of template parameters first.)
I could write a lot of overloads for every pair of types, but this is just really ugly. I tried making multiply a template variable without a template class, and even though I'm using C++14, got cannot resolve address of overloaded function at multiply_ with this alternative definition:
template<class T, class F>
auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
template<class T, class F>
Chunk<decltype(multiply_)> multiply = toChunk([]() { return multiply_; });
Of course I then changed ops::multiply to simply multiply. Any suggestions to overcome this?
ops is a name of a class template. To refer to members of a class template outside of its definition you need to specify the template arguments.
If you fix this error though, there are going to be more.
I ended up using an entirely different solution. I overloaded apply by adding this second definition:
template<class F, class... Args>
auto apply(F f, Args... as) -> decltype(f(as...))
{
return f(as...);
}
And rewrote multiply as simply:
auto multiply = [](auto x, auto y) { return x * y; };
So our library functions will not be in the lazy wrappers, while user-defined functions (which can't be templates in our language) will.

Is it possible to use parameter pack to allow template function to accept equivalent types?

This question is related to one on SO a couple of years ago by Georg Fritzsche about transforming a parameter pack (Is it possible to transform the types in a parameter pack?). In the end, the individual types in the parameter pack can be transformed, e.g. by converting to corresponding pointer types.
I am wondering if it is possible to use this technique to write one standard function/functor and a set of wrapper functions (out of one template), so that the wrappers can take parameters of equivalent types and then call the standard function to do actual work.
Using the answer by Johannes Schaub - litb the original example below. Is it possible to write one template f, which can take any combinations of int/int*,char/char* and call a common function f_std(int*,char*) to do the work. (The number of parameters is not pre-specified.)
--- Update ---
For example, given int i; char c;, is it possible to write a caller using pack transformation such that the following works
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
What I've tried so far is listed below (updated to clarify.). Basically, I tried to accept an list of not necessarily pointer types and convert them to pointer types, before making call to a std::function that takes pointer types. But the code does not compile. I don't know how to write a helper function to accept one function with a standard signature, but accept a parameter pack of something else.
Thanks in advance
#include <type_traits>
#include <functional>
using namespace std;
template<class... Args> struct X {};
template<class T> struct make_pointer { typedef T* type; };
template<class T> struct make_pointer<T*> { typedef T* type; };
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
/////////////////
// trying to convert parameter pack to pointers
template<class T> T* make_ptr(T x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
template <typename Value, typename ...Args>
class ByPtrFunc
{
public:
typedef typename magic<X, make_pointer, Args...>::type PArgs;
Value operator()(Args... args) { return f(make_ptr(args)...); }
private:
std::function<Value (PArgs...)> _ptr_func;
}; //ByPtrFunc
//helper function to make call
template<typename A, typename ...Args>
static A call_ptr(std::function<A (Args...)> f, Args... args) {
return ByPtrFunc<A, Args...>{f}(args ...);
}
int main() {
typedef magic<X, make_pointer, int*, char>::type A;
typedef X<int*, char*> B;
static_assert(is_same<A, B>::value, ":(");
int i=0; char c='c';
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
//////////////////
//Is the following possible.
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
return 0;
}
This answers your question syntax-wise, if I've understood it correctly: yes, it's possible.
// given int or char lvalue, returns its address
template<class T>
T* transform(T& t) {
return &t;
}
// given int* or char*, simply returns the value itself
template<class T>
T* transform(T* t) {
return t;
}
// prints out the address corresponding to each of its arguments
void f_std() {
}
template<class Arg, class... Args>
void f_std(Arg arg, Args... args) {
std::cout << (void*)arg << std::endl;
f_std(args...);
}
// converts int to int*, char to char*, then calls f_std
template<class... Args>
void f(Args... args) {
f_std(transform(args)...);
}
Unfortunately, calling f will pass int and char arguments by value, and hence copy them. To fix this, use perfect forwarding in the definition of f:
template<class... Args>
void f(Args&&... args) {
f_std(transform(std::forward<Args>(args))...);
}
Driver:
int main() {
int x = 1;
char c = 'a';
cout << (void*)&x << endl;
cout << (void*)&c << endl;
f(x, &x, c, &c);
}
Output (example; ran it on my machine just now):
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebc
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebb
Following may help:
template <typename T> T* make_pointer(T& t) { return &t; }
template <typename T> T* make_pointer(T* t) { return t; }
template <typename Ret, typename... Args, typename ...Ts>
Ret call_ptr(std::function<Ret (Args*...)> f, Ts&&...args)
{
static_assert(sizeof...(Args) == sizeof...(Ts), "Bad parameters");
f(make_pointer(std::forward<Ts>(args))...);
}
Now, use it:
void f_std(int*, char*) { /* Your code */ }
int main(int argc, char *argv[])
{
int i;
char c;
std::function<void (int*, char*)> f1 = f_std;
call_ptr(f1, i, c);
call_ptr(f1, i, &c);
call_ptr(f1, &i, c);
call_ptr(f1, &i, &c);
return 0;
}
For reference, below is what worked for me, based on the accepted answer #Jarod42 and the type transformation "magic". slightly more general and with added type checking. Turns out type-transformation is simply a pattern expansion.
#include <type_traits>
#include <functional>
#include <iostream>
using namespace std;
/////////////////
// convert parameter pack to pointers
//types
template<class T> struct make_ptr_t { typedef T* type; };
template<class T> struct make_ptr_t<T*> { typedef T* type; };
//values
template<class T> T* make_ptr(T& x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
/////////////////////////////////////
// (optional) only for type checking
template<class... Args> struct X {};
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
//helper function to make call
template<typename A, typename ...PArgs, typename ...Args>
static A call_ptr(std::function<A (PArgs...)> f, Args... args) {
static_assert(is_same<X<PArgs...>,typename magic<X, make_ptr_t, Args...>::type>::value, "Bad parameters for f in call_ptr()"); //type checking
return f(make_ptr(args)...);
}
int main() {
int i=0; char c='c'; string s="c";
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
cout << call_ptr(f_std,i,c) << endl;
cout << call_ptr(f_std,&i,c) << endl;
cout << call_ptr(f_std,i,&c) << endl;
//cout << call_ptr(f_std,i,s) << endl; //complains about bad parameters.
return 0;
}

How std::function works

You know, we can wrap or store a lambda function to a std::function:
#include <iostream>
#include <functional>
int main()
{
std::function<float (float, float)> add = [](float a, float b)
// ^^^^^^^^^^^^^^^^^^^^
{
return a + b;
};
std::cout << add(1, 2) << std::endl;
}
My question is around std::function, as you can see it is a template class but it can accept any kind of function signature.
For example float (float, float) in this form return_value (first_arg, second_arg).
What's the structure of std::function and how does it accept a function signature like x(y,z) and how it works with it? Is float (float, float) a new valid expression in C++?
It uses some type erasure technique.
One possibility is to use mix subtype polymorphism with templates. Here's a simplified version, just to give a feel for the overall structure:
template <typename T>
struct function;
template <typename Result, typename... Args>
struct function<Result(Args...)> {
private:
// this is the bit that will erase the actual type
struct concept {
virtual Result operator()(Args...) const = 0;
};
// this template provides us derived classes from `concept`
// that can store and invoke op() for any type
template <typename T>
struct model : concept {
template <typename U>
model(U&& u) : t(std::forward<U>(u)) {}
Result operator()(Args... a) const override {
t(std::forward<Args>(a)...);
}
T t;
};
// this is the actual storage
// note how the `model<?>` type is not used here
std::unique_ptr<concept> fn;
public:
// construct a `model<T>`, but store it as a pointer to `concept`
// this is where the erasure "happens"
template <typename T,
typename=typename std::enable_if<
std::is_convertible<
decltype( t(std::declval<Args>()...) ),
Result
>::value
>::type>
function(T&& t)
: fn(new model<typename std::decay<T>::type>(std::forward<T>(t))) {}
// do the virtual call
Result operator()(Args... args) const {
return (*fn)(std::forward<Args>(args)...);
}
};
(Note that I overlooked several things for the sake of simplicity: it cannot be copied, and maybe other problems; don't use this code in real code)

Can a template parameter itself be templatized?

Say I have the following code:
#include <iostream>
#include <functional>
template <int func(int)>
struct S : std::unary_function<int, int>
{
int operator()(int x) const
{
return func(x);
}
};
int foo(int x)
{
return x;
}
int main()
{
S<foo> s;
std::cout << s(42) << std::endl;
}
This works okay as a way of wrapping up a function inside of a functor, which means it can be used in other templated functions (like sort, for example (assuming the functor had the right signature)). I don't want to create a functor struct for every possible return/argument type (and realistically I can't), and so I tried the following:
template <template <typename R, // Make the return type and argument type template parameters!
typename A> R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
That didn't work; it gave me compilation errors. So then I tried:
template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
Which did work. Unfortunately though, I had to change instantiations of S to be S<int, int, foo> s; instead of the nicer S<foo> s;.
Is it at all possible to templatize the function passed as a template argument such that I can do S<foo> s; and not hard code the return type and argument type of the function in S?
My google-foo hasn't been able to find a specific answer.
Edit: Now I'm wondering if this isn't possible. I just thought of "what if foo is an overloaded function?" There wouldn't be, as far as I know, a way to know which foo to use when saying S<foo> s; and thus explicitly stating return/argument type is necessary. Is this correct thinking, and does this mean that the answer to my first question is "No, it's not possible"?
Unfortunately, I think it's the only way to prevent necessary conversions for passing functions.
But you can add function templates to help you deduce the types of (1) function args (2) function returns, like codes below:
template < typename R, typename A >
R result_of( R(A) );
template < typename R, typename A >
A arg0_of( R(A) );
Then you can use them to construct wanted function objects and let compilers do possible optimizations:
#define get_call( f ) call_t< decltype(result_of(f)), \
decltype(arg0_of(f)), f >()
// same as the class 'S'
template < typename R, typename A,
R unary( A ) >
struct call_t : std::unary_function<A,R> {
R operator()( A arg ) const {
return unary( arg );
}
};
Use the utility:
int neg( int arg ) {
return -arg;
}
auto s = get_call( neg );
cout << s( 1 ) << endl; // outputs: -1
It works too on function templates. Of course, you have to pass argument(s) to the template:
template < typename T >
T square( T arg ) {
return arg * arg;
}
template <>
int square( int arg ) {
cout << "square<int>()" << endl;
return arg * arg;
}
auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
// 144
Edit: for overloaded functions, you can do conversions to tell compilers which version you wanna invoke:
int cube( int arg ) {
return arg * arg * arg;
}
float cube( float arg ) {
return arg * arg * arg;
}
typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000
You seem to want to have a non-type template template parameter. However, the only legal syntax for template template parameters is template < template-parameters > class. ("A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression." § 14.3.3)
You could create a templated class whose constructor argument was a function pointer, but I'm guessing that you're worried that will create an indirect function call.
That is not possible. It is the same problem in principle as the following one: you wish to write just A<100> where A is defined as:
template<T N>
struct A {};
Given N is 100, T turns out to be int. Fine. That is deducible by human mind, but not by the compilers even if they be 100% conformant to the C++11 Standard. I've exactly the same problem here:
Pretty-print types and class template along with all its template arguments
--
So the alternative solution I think is this:
template <typename R, typename A>
struct S : std::unary_function<R, A>
{
typedef R (*Fun)(A);
Fun func;
S(Fun f) : func(f) {}
R operator()(A arg) const
{
return func(arg);
}
};
And then define MakeS function as:
template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A))
{
return S<R,A>(fun);
}
Which you can use it as:
auto s = MakeS(foo);
Or, simply this:
S<int,int> s(foo);
The downside with this alternative is that the function foo doesn't have any chance to be inlined now.
Does this work for you?
It may not be as nice as S<foo> but keeps the arguments as 1 at the point of instantiation.
int f(int) { return 0; }
template<class R, class A> struct S
{
typedef R(*FTYPE)(A);
typedef R RET;
typedef A ARG;
};
template<class R, class A> S<R, A> FW(R(f)(A));
template<class T> struct F : std::unary_function<typename T::RET, typename T::ARG>
{
};
int main()
{
F<decltype(FW(f))> o;
}