#include <iostream> // For std::cout, std::boolalpha, std::endl.
#include <string>
#include <cstdint> // For int16_t.
#include <type_traits> // For is_void<T>.
using FilePath = std::string;
// ---------------------
// ExecuteMethod() functor:
// ---------------------
// Default functor.
template<typename... Ts>
struct Executor { };
// General case.
template<typename M, typename ReturnType, typename... Params>
struct Executor<M, ReturnType (*)(Params...)> {
public:
// Parameter match:
bool operator()(M method, Params... params) {
ReturnType r = method(params...);
std::cout << "Valid call. Return value: " << r << "." << std::endl;
return true;
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
std::cout << "Invalid call." << std::endl;
return false;
}
};
// Special case to catch void return type.
template<typename M, typename... Params>
struct Executor<M, void (*)(Params...)> {
public:
// Parameter match:
bool operator()(M method, Params... params) {
method(params...);
std::cout << "Valid call. Return value: None, 'cuz it's void." << std::endl;
return true;
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
std::cout << "Invalid call." << std::endl;
return false;
}
};
#define ExecuteMethod(C, M, ...) \
do { \
Executor<decltype(&M), decltype(&M)> temp; \
C = temp(M, ##__VA_ARGS__); \
} while (false)
// ---------------------
// Example functions:
// ---------------------
int GetColor(int16_t* color) { *color = 0xF249; return 42; }
int GetFile(FilePath& file) { std::cout << "You want " << file << "? You can't handle the file!" << std::endl; return 24; }
int WriteDocument(const FilePath &file, const char *fileFormatName, bool askForParms) { std::cout << "Do it yerself!" << std::endl; return 195; }
// Returns gibberish, to lighten everyone's day.
int f0(int a) { std::cout << "You passed " << a << std::endl; }
bool f1(int& a, const float b) {
std::cout << ((b > a) ? "b's bigger." : "a's bigger.") << std::endl;
return (a > b);
}
float f2(float* a, const float* b) { return ++(*a) * (*b); }
char f3() { return 'c'; }
void f4(std::string& s) { s = "A different string."; }
// ---------------------
// main():
// ---------------------
int main() {
int a = 8;
float b1 = 2.0, b2 = 3.14;
bool c = false;
std::int16_t i16 = 0b1100010100001111; // Suddenly, binary literal!
std::string s = "A string.";
FilePath fp = "C:\\Windows\\system32\\chkntfs.exe";
std::cout << "Testing:" << std::endl;
std::cout << "- - -" << std::endl;
std::cout << std::boolalpha;
std::cout << "(int(*)(int), int):" << std::endl;
ExecuteMethod(c, f0, a);
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "(int(*)(int), int, float):" << std::endl;
ExecuteMethod(c, f0, a, b1);
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "(bool(*)(int&, const float), int&, const float):" << std::endl;
ExecuteMethod(c, f1, a, b1);
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "(float(*)(float*, const float*):" << std::endl;
ExecuteMethod(c, f2, &b1, &b2);
std::cout << "Well, then. Once again, with const-ness!" << std::endl;
std::cout << "Old values: " << b1 << ", " << b2 << std::endl;
ExecuteMethod(c, f2, &b1, const_cast<const float*>(&b2));
std::cout << "New values: " << b1 << ", " << b2 << std::endl;
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "(char(*)()):" << std::endl;
ExecuteMethod(c, f3);
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "Reference testing:" << std::endl;
std::cout << "(void(*)(std::string&), std::string&):" << std::endl;
std::cout << "Original string: \"" << s << "\"" << std::endl;
ExecuteMethod(c, f4, s);
std::cout << "New string: \"" << s << "\"" << std::endl;
std::cout << "c: " << c << std::endl << std::endl;
std::cout << std::endl;
std::cout << "Now, let's try your example functions:" << std::endl;
std::cout << "- - -" << std::endl;
std::cout << "int GetColor(int16_t*):" << std::endl;
std::cout << "Old value: " << i16 << std::endl;
ExecuteMethod(c, GetColor, &i16);
std::cout << "New value: " << i16 << std::endl;
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "int GetFile(FilePath&):" << std::endl;
ExecuteMethod(c, GetFile, fp);
std::cout << "c: " << c << std::endl << std::endl;
std::cout << "int WriteDocument(const FilePath&, const char*, bool):" << std::endl;
ExecuteMethod(c, WriteDocument, fp, s.c_str(), true);
std::cout << "c: " << c << std::endl << std::endl;
}