I have the functionWrapper
class, which should encapsulate function.
It works fine but arguments are unable to being passed by reference.
Here is the code:
#include <iostream>
#include <functional>
#include <tuple>
#include <type_traits>
template <typename T>
struct function_traits;
// Specialization for function pointers
template <typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> {
using return_type = Ret;
using args_type = std::tuple<Args...>;
};
// Specialization for std::function
template <typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> {
using return_type = Ret;
using args_type = std::tuple<Args...>;
};
// Specialization for lambdas and functors
template <typename T>
struct function_traits : function_traits<decltype(&T::operator())> {};
class functionWrapper {
template <typename... Args>
class B;
class A {
public:
template <typename F>
static auto castToB(F func) {
using ArgsTuple = typename function_traits<F>::args_type;
return castToBImpl(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>{}, func);
}
virtual ~A(){}
private:
template <std::size_t... Is, typename F>
static auto castToBImpl(std::index_sequence<Is...>, F func) {
// Create B with the correct argument types based on the number of arguments
return new B<typename std::tuple_element<Is, typename function_traits<F>::args_type>::type...>(func);
}
};
template <typename... Args>
class B : public A {
public:
std::function<void(Args...)> function;
template <typename F>
B(F f) : function(f) {}
virtual ~B(){}
};
private:
A* ptr = nullptr;
public:
template <typename F>
functionWrapper(F f) {
ptr = static_cast<A*>(A::castToB(f));
}
functionWrapper(){}
virtual ~functionWrapper(){
delete ptr;
}
template <typename... Args>
void operator()(Args... args) {
if (ptr)
static_cast<B<Args...>*>(ptr)->function(std::forward<Args...>(args...));
}
};
Using:
void foo(int& a){
std::cout << a++ << '\n';
}
int main() {
int a = 5;
functionWrapper wrap{foo};
wrap(a);
std::cout << a << '\n';
return 0;
}
Output is:
5
5
Instead of expected:
5
6
Changed this:
template <typename... Args>
void operator()(Args... args) {
if (ptr)
static_cast<B<Args...>*>(ptr)->function(std::forward<Args...>(args...));
}
To this:
template <typename... Args>
void operator()(Args&&... args) {
if (ptr)
static_cast<B<Args...>*>(ptr)->function(std::forward<Args>(args)...);
}
Looks like its working correctly