Of course your wish can be achieved.
You may use a combination of
std::any
, which can store any function
- a 'std::map', where you can associate a selector with a function
- and a variadic parameter pack, which can be any kind and number of parameters
We will create a class and store all functions (any number) together with a selector in a std::map
. We add functionality to the class, so that we can add an arbitrary number of functions.
We can also use a std::initializer_list
for braced initialization of the class.
Then we add a "caller function" with a selector and call the wished function.
Please see the simple example below:
#include <iostream>
#include <map>
#include <string>
#include <any>
#include <utility>
class Caller
{
std::map<int, std::any> selector;
public:
Caller() : selector() {}
Caller(std::initializer_list<std::pair<const int, std::any>> il) : selector(il) {}
template<typename Function>
void add(int key, Function&& someFunction) { selector[key] = std::any(someFunction); };
template <typename ... Args>
void call(int key, Args ... args) {
if (selector.find(key) != selector.end()) {
std::any_cast<std::add_pointer_t<void(Args ...)>>(selector[key])(args...);
}
}
};
// Some demo functions
void a(int x) {
std::cout << "a\t" << x << '\n';
};
void b(int x, int y) {
std::cout << "b\t" << x << '\t' << y << '\n';
};
void c(int x, int y, std::string z) {
std::cout << "c\t" << x << '\t' << y << '\t' << z << '\n';
};
void d(std::string s, int x, int y, int z) {
std::cout << "d\t" << s << '\t' << x << '\t' << y << '\t' << z << '\n';
};
// Definition of our caller map (using initializer list)
Caller caller{
{1, a},
{2, b},
{3, c}, };
int main() {
// Some demo calls
caller.call(1, 1);
caller.call(2, 1, 2);
caller.call(3, 1, 2, std::string("3"));
// Adding an additional function
caller.add(4, d);
// And call this as well.
caller.call(4, std::string("ddd"), 1, 2, 3);
return 0;
}
Translated to your needs this could be:
#include <iostream>
#include <string>
#include <unordered_map>
#include <any>
using namespace std::string_literals;
// Your functions
void functionCandidate1(int arg1, std::string arg2) { std::cout << "Function 1: " << arg1 << '\t' << arg2 << '\n'; }
void functionCandidate2(int arg1, long arg2) { std::cout << "Function 2: " << arg1 << '\t' << arg2 << '\n'; }
// The class
class MyClass {
// Storage for function
std::unordered_map<bool, std::any> class_function_ {{true, functionCandidate1},{false, functionCandidate2}};
// What function to use
bool selector{};
public:
// Constructor: Select function
MyClass(const bool& use_function_candidate_1 = true) : selector(use_function_candidate_1) {}
// Function caller
template <typename ... Args>
void call(Args ... args) {std::any_cast<std::add_pointer_t<void(Args ...)>>(class_function_[selector])(args...); }
};
int main() {
// Test with default argument
MyClass mc1{};
mc1.call(1, "abc"s);
// Test with true for function 1
MyClass mc2{};
mc2.call(2, "def"s);
// Test with false for function 2
MyClass mc3{false};
mc3.call(3, 3L);
}