Properly implementing an array of class functions - c++

I want to make an array of known size of class functions. To do so, I've tried using typedef, but it hasn't been working out so far.
Also, some functions take no arguments ex. F(), but others do ex. G(int n), and in the typedef, I don't know how to tell it to accept no arguments for some (tried void but it says it is not a type), and to accept arguments for others.
class myClass
{
// An array of void functions
typedef void(myClass::*arrayOfFunctions)();
private:
arrayOfFunctions array[3] = { &myClass::F, &myClass::G, &myClass::H };
void F() { do stuff; }
void G(int n) { do stuff involving n; }
void H() { do stuff; }
};
What I have tried:
I have successfully made an array of void functions in a main with no classes involved which I can call when wanted, so part of the problem seems to be implementing this in a class and using its class functions.
// This works:
typedef void(*arrayOfFunctions)();
void Action1()
{
// stuff 1
}
void Action2()
{
// stuff 2
}
void Action3()
{
//stuff3
}
int main()
{
arrayOfFunctions functionArray[] = { Action1, Action2, Action3 };
// Call Action1
functionArray[0]();
return 0;
)

As was mentioned in comments, it is not possible directly. You cannot store objects of different type in the same array. However, there are ways to achieve what you want. How to get there very much depends on details. Latest when you call the function you need to know how many parameters to pass.
In your example one possibility is to refactor to have only methods with no parameters:
class myClass {
using memFun = void(myClass::*)();
void set_n(int x) { n = x; }
private:
memFun array[3] = { &myClass::F, &myClass::G, &myClass::H };
void F() { do stuff; }
void G() { do stuff involving n; }
void H() { do stuff; }
int n;
};
I changed the name of the alias, because it is just the type of a function pointer not an array. using is easier to read than typedef (it follows the more common x = something style).
When you call the function G the parameter n has to come from somewhere, so instead of passing it directly you can call set_n before iterating the array and call all mehtods without parameter.

It is not clear how you want to use such an array. If you know an element index at compile time, then you could probably use a std::tuple with template argument deduction. For example:
class my_class {
public:
template<std::size_t n, class... Args>
decltype(auto) call_fn(Args&&... args) {
constexpr auto ptrs = get_fn_pointers();
return std::invoke(std::get<n>(ptrs), this, std::forward<Args>(args)...);
}
private:
static constexpr auto get_fn_pointers() {
return std::tuple(&my_class::f, &my_class::g, &my_class::h);
}
void f() {
std::cout << "f()\n";
}
void g(int n) {
std::cout << "g(" << n << ")\n";
}
int h() {
std::cout << "h() => ";
return 9102;
}
};
int main() {
my_class c;
c.call_fn<0>(); // Output: f()
c.call_fn<1>(2019); // Output: g(2019)
std::cout << c.call_fn<2>(); // Output: h() => 9102
}

Related

Is there a better way to provide this function to a constructor?

I have a class A which has a constructor with a function argument: i.e.
class A {
public:
A(int (*f)(int);
};
I can create this class and have it use func() with, for example,
int func(int n);
A a(func);
I would like to invoke this class a number of times, but have it use internally func(n)+m instead of func(n). I would prefer not to change class A. I could create a new class to define the function I want
class B {
int (*func)(int n);
int m;
public:
B(int (*ff)(int),int mm) : func(ff),m(mm) {}
int myfunc(int n) { return(func(n)+m);
};
However, I don't think it is possible to convert a pointer to myfunc into a pointer with the required signature for A's constructor.
The way I have chosen is similar to the above, but with myfunc() and associated variables stored in the global space:
int m;
int (*func)(int);
int myfunc(int n) { return(func(n)+m); }
void setupmyfunc(int mm,int (*ff)(int)) { m=mm; func=ff; }
Then I can can create my A object with
setupmyfunc(m,func);
A a(myfunc);
This works, but seems inelegant to me. Is there a better way?
Stateless lambdas are implicitly convertible to function pointers so you can just use that without modifying your class A and without creating another class B. That is if I understood your question correctly.
class A {
public:
A(int (*f)(int)) {};
};
int func(int n) { return n * 10; }
auto test()
{
A a{[](int n) { return func(n) + 1; }};
}
std::function can hold callable objects (functions, function objects, member function pointers (with object to bind to), etc. It uses some type-erasure such that it can have this genericity, but comes at the cost of internal overhead to actually invoke it, often equivalent to a virtual function call.
Here's an example, where A takes a std::function, which allows you to pass in lambdas.
#include <functional>
#include <iostream>
class A {
std::function<int(int)> func_;
public:
A(std::function<int(int)> func) : func_(func) {}
int call(int x) {
return func_(x);
}
};
int foo(int x) {
return x * 123; // whatever
}
int main() {
// here's your wrapper function to do func(x)+m (m==9 in this case)
A obj([](int x) { return foo(x) + 9; });
int result = obj.call(123);
std::cout << result << '\n';
}
https://godbolt.org/z/94MfGM67K
Update:
Given the rejection of both answers so far, using std::function is out because it changes class A, and the obvious use of state-full lambdas for composition and capturing customization data is also out, you will need to get more creative and possibly ugly. If you can't change A, then you can't change the signature of the function passed to a, so making the lambda take its data as another argument is also out.
Seems to me that leaves just one thing: using state that is outside the function (i.e. global data or encoded in a template non-type template parameter) as a form of pseudo-capture that an otherwise stateless function can use. I reject the global approach in general, though there's interesting aspects to it, and only present a template solution:
Now you write your free-standing functions and can compose them with a template:
#include <iostream>
using F = int(*)(int);
class A {
public:
A(F f) : f_(f) { }
int operator()(int x) { return f_(x); } // Added for demo
private:
F f_;
};
template <F FuncF, F FuncG>
int compose(int n) {
return FuncF(FuncG(n));
}
int func(int n) { return n * 1000; }
int add888(int n) { return n + 888; }
int add999(int n) { return n + 999; }
int main() {
A a1(compose<add888, func>);
A a2(compose<add999, func>);
std::cout << a1(1) << " " << a2(1) << " " << a1(1);
}
// output: 1888 1999 1888
https://godbolt.org/z/8KsqbTcTd
This works as far back as c++11, and replacing the "using" with "typedef" it work in C++98.

Call a C-style function address with std::bind and std::function.target using a method from object

I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}

Passing an inherited method to another method

I am trying to build a class that has a member function with a method as argument. The methods are defined in inherited classes. I build a minimal example:
#include <iostream>
struct base
{
base() {}
int number(int (*f)(int))
{
return f(1);
}
};
struct option1 : base
{
int timesTwo(int i){return 2*i;}
option1()
{
std::cout << number(timesTwo);
}
};
struct option2 : base
{
int timesThree(int i){return 3*i;}
int timesFour (int i){return 4*i;}
option2()
{
std::cout << number(timesThree);
}
};
int main()
{
option1 a; //I would expect this to print "2"
}
The current syntax in the function number is for a general function, but I cannot get it to work for a method of any inherited classes.
The problem here is that you're passing a pointer to a member function, which is completely different from a pointer to a non-member function (which is what your number function takes as an argument).
You could use std::function and std::bind:
int number(std::function<int(int)> f)
{
return f(1);
}
...
number(std::bind(&option1::timesTwo, this, _1));
You could also use templates, and extra arguments, like
template<typename T>
int number(T* object, int(T::*f)(int))
{
return (object->*f)(1);
}
...
number(this, &option1::timesTwo);
Or the simple (but not always correct, depending on situation and use case): Make the callback-function static:
static int timesTwo(int i){return 2*i;}
My recommendation is that you look over the solution using std::function, because then it's easy to call the number function with any type of callable object, like a lambda:
number([](int x){ return x * 2; });
The given error says :
error: reference to non-static member function must be called
You can just add static before your method members.
And I would suggest you to use std::function instead of pointer functions.
A working code :
#include <iostream>
#include <functional>
struct base
{
base() {}
int number(std::function<int(int)> f)
{
return f(1);
}
};
struct option1 : base
{
static int timesTwo(int i){return 2*i;}
option1()
{
std::cout << number(timesTwo);
}
};
struct option2 : base
{
static int timesThree(int i){return 3*i;}
static int timesFour (int i){return 4*i;}
option2()
{
std::cout << number(timesThree);
}
};
int main()
{
option1 a; // now it works
}

using function object though function pointer is required

I have to use some legacy code expecting a function pointer, let's say:
void LEGACY_CODE(int(*)(int))
{
//...
}
However the functionality I have is within a functor:
struct X
{
Y member;
X(Y y) : member(y)
{}
int operator()(int)
{
//...
}
};
How should I modify/wrap class X so that LEGACY_CODE can access the functionality within X::operator()(int) ?
Your question makes no sense. Whose operator do you want to call?
X a, b, c;
LEGACY_CODE(???); // what -- a(), b(), or c()?
So, in short, you cannot. The member function X::operator() is not a property of the class alone, but rather it is tied to an object instance of type X.
Search this site for "member function" and "callback" to get an idea of the spectrum of possible approaches for related problems.
The crudest, and quite possibly not-safe-for-use, workaround to providing a free function would go like this:
X * current_X; // ugh, a global
int dispatch(int n) { current_X->operator()(n); }
int main()
{
X a;
current_X = &a;
LEGACY_CODE(dispatch);
}
You can see where this is going...
A simple wrapper function looks like:
int wrapperfunction(int i) {
Functor f(params);
return f(i);
}
If you want to be able to pass the parameters to the functor itself, the simplest way is to sneak them in using (brr) a global variable:
Functor functorForWrapperfunction;
int wrapperfunction(int i) {
functorForWrapperfunction(i);
}
// ...
void clientCode() {
functorForWrapperfunction = Functor(a,b,c);
legacyCode(wrapperfunction);
}
You can wrap it with a class with a static method and a static member if you want.
Here's one compile-time solution. Depending on what you need, this might be a too limited solution for you.
template<typename Func, int Param>
int wrapper(int i)
{
static Func f(Param);
return f(i);
}
A thread-safe version under the restriction that the legacy code is not called with different parameters in a thread.
IMHO, one cannot get rid of global storage.
#include <boost/thread.hpp>
#include <boost/thread/tss.hpp>
class AA
{
public:
AA (int i) : i_(i) {}
void operator()(int j) const {
static boost::mutex m; // do not garble output
boost::mutex::scoped_lock lock(m);
std::cout << " got " << j << " on thread " << i_ << std::endl;
Sleep(200); }
int i_;
};
// LEGACY
void legacy_code(void (*f)(int), int i) { (*f)(i); }
// needs some global storage through
boost::thread_specific_ptr<AA> global_ptr;
void func_of_thread(int j)
{
AA *a = global_ptr.get();
a->operator()(j);
}
void worker(int i)
{
global_ptr.reset(new AA(i));
for (int j=0; j<10; j++)
legacy_code(func_of_thread,j);
}
int main()
{
boost::thread worker1(worker,1) , worker2(worker,2);
worker1.join(); worker2.join();
return 0;
}

Is it possible to have a function(-name) as a template parameter in C++?

I don't want function pointer overhead, I just want the same code for two different functions with the same signature:
void f(int x);
void g(int x);
...
template<typename F>
void do_work()
{
int v = calculate();
F(v);
}
...
do_work<f>();
do_work<g>();
Is this possible?
To clear up possible confusion: With "template parameter" I mean the parameter/argument to the template and not a function parameter whose type is templated.
Your idea's ok, but you're not passing in a type but a value (specifically, a function pointer>. Alternatively, pass a template policy providing functions - it's a good idea to read Modern C++ Design by Andrei Alexandrescu.
#include <iostream>
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef int (*F)(int);
template<F f>
int do_work()
{
return f(7);
}
int main()
{
std::cout << do_work<f>() << '\n'
<< do_work<g>() << '\n';
}
OR
int calculate() { return 4; }
struct F { int do_something_with(int x) { return 2 * x; } };
struct G { int do_something_with(int x) { return -3 * x; } };
// or, make these functions static and use Operator::do_something_with() below...
template<typename Operation>
int do_work()
{
int v = calculate(7);
return Operation().do_something_with(v);
}
int main()
{
std::cout << do_work<F>() << '\n'
<< do_work<G>() << '\n';
}
One approach that is highly likely to generate the direct function call, because it gives the compiler no option, is to use a static member function:
struct F { static void func(int x) { /*whatever*/ } };
struct G { static void func(int x) { /*whatever*/ } };
template<class T>
void do_work() {
T::func(calculate());
}
No function pointers, no temporaries, and no unnecessary this. I guarantee nothing, of course, but generated code should be reasonable even with optimization disabled.
You can have pointers to functions as template parameters, but function objects are more "C++ish". However, you can write your function template in a way that accepts both variants:
#include <iostream>
void f(int x)
{
std::cout << "inside function f\n";
}
struct g
{
void operator()(int x)
{
std::cout << "inside function object g\n";
}
};
template <typename Functor>
void do_work(Functor fun)
{
fun(42);
}
int main()
{
// template argument is automatically deduced
do_work(&f);
// but we could also specify it explicitly
do_work<void(*)(int)>(&f);
// template argument is automatically deduced
do_work(g());
// but we could also specify it explicitly
do_work<g>(g());
}
Here, the name Functor hints at any type that is callable via f(x) syntax. Functions support this syntax naturally, and in the case of function objects, f(x) is syntactic sugar for f.operator()(x).
No, you need to wrap the functions in a wrapper class with operator(). Here is an example:
class Functor_f
{
public:
void operator()(int x)
{
}
};
class Functor_g
{
public:
void operator()(int x)
{
}
};
template<typename F>
void do_work()
{
F f;
int v = calculate();
f(v);
}
int main()
{
do_work<Functor_f>();
do_work<Functor_g>();
}
You can use std::ptr_fun to do this wrapping automatically for you. For example:
void f(int x)
{
}
void g(int x)
{
}
template<typename F>
void do_work(F f)
{
int v = calculate();
f(v);
}
int main()
{
do_work(std::ptr_fun(f));
do_work(std::ptr_fun(g));
}
With any modern C++ compiler you don't pay the function pointer overhead when the function pointer value is known at compile time, like in your example, because the compiler then replaces the indirection with a direct function call.
Consider your example code, slightly modified:
void f(int x);
void g(int x);
int calculate();
template<typename F>
void do_work(F f)
{
int v = calculate();
f(v);
}
static void trabajar(void (f)(int))
{
int v = calculate();
f(v);
}
void foo()
{
do_work(f);
do_work(g);
}
void bar()
{
trabajar(f);
trabajar(g);
}
void baz()
{
f(calculate());
g(calculate());
}
For all the foo(), bar() and baz() variants GCC 12.1 generates the same direct function invoking code:
sub rsp, 8
call calculate()
mov edi, eax
call f(int)
call calculate()
add rsp, 8
mov edi, eax
jmp g(int)
See also: compiler explorer
Notes:
foo() and bar() invoke f() and g() via function pointers
baz() invokes f() and g() directly
for you use case it isn't necessary to templatize your do_work() function, i.e. trabajar() is the non-template version that only accepts function pointers
templating do_work() like this has the advantage that you can also supply some compatible function object (functor) instead of a function pointer
when templating do_work() like this and supplying a function address as its argument (like in foo()), the template parameter F is type-inferred to void (*)(int), i.e. a function pointer type
It's perhaps worth mentioning that even when using a C++ function object there isn't really a guarantee that your C++ compiler inlines the classes function call operator. However, any serious C++ will do it.