The following code uses the indices trick twice in order to:
- convert the string arguments to the respective type
- call the desired function with the converted arguments.
The code uses std::integer_sequence
from C++14, but this can easily be converted to C++11 if necessary.
#include <iostream>
#include <stack>
#include <utility>
#include <string>
using Stack = std::stack<std::string>;
template <typename Type>
Type translate_argument(const std::string&);
template<>
int translate_argument<int>(const std::string& str)
{
return std::stoi(str);
}
template <typename Type>
Type translate_arg(Stack& stack)
{
Type value = translate_argument<Type>(stack.top());
stack.pop();
return value;
}
template <typename Type>
std::string translate_result(const Type& result)
{
return std::to_string(result);
}
template <typename Tuple, std::size_t... Indices>
Tuple call_translate_arg_detail(Stack& stack, Tuple, std::index_sequence<Indices...>)
{
return Tuple{translate_arg<typename std::tuple_element<Indices, Tuple>::type>(stack)...};
}
template <typename... Args>
std::tuple<Args...>
call_translate_arg(Stack& stack)
{
return call_translate_arg_detail(stack,
std::tuple<Args...>{},
std::index_sequence_for<Args...>{}
);
}
template <typename Tuple, size_t... Indices, typename Ret, typename... Args>
Ret
call_fun_detail(Tuple& tuple, Ret(*fun)(Args...), std::index_sequence<Indices...>)
{
return fun(std::get<Indices>(tuple)...);
}
template <typename Tuple, typename Ret, typename... Args>
Ret
call_fun(Tuple& tuple, Ret(*fun)(Args...))
{
return call_fun_detail(tuple,
fun,
std::make_index_sequence<std::tuple_size<Tuple>::value>{}
);
}
template <typename Signature, Signature function>
struct Function;
template <typename Ret, typename... Args, Ret(*fun)(Args...)>
struct Function<Ret(Args...), fun>
{
static void call(Stack& stack)
{
auto arg_tuple = call_translate_arg<Args...>(stack);
Ret result = call_fun(arg_tuple, fun);
stack.push(translate_result(result));
}
};
// specialization for void return value
template <typename... Args, void(*fun)(Args...)>
struct Function<void(Args...), fun>
{
static void call(Stack& stack)
{
auto arg_tuple = call_translate_arg<Args...>(stack);
call_fun(arg_tuple, fun);
}
};
Demo:
void foo(int x, int y)
{
std::cout << "foo: x=" << x << " y=" << y << std::endl;
}
int bar(int x, int y, int z)
{
int result = x+y+z;
std::cout << "bar: x=" << x << " y=" << y << " z=" << z << std::endl;
std::cout << "bar: result=" << result << std::endl;
return result;
}
int main()
{
Stack stack;
stack.push("10");
stack.push("20");
stack.push("30");
Function<decltype(bar), bar> bar_fun;
bar_fun.call(stack);
stack.push("100");
Function<decltype(foo), foo> foo_fun;
foo_fun.call(stack);
return 0;
}
Output:
bar: x=30 y=20 z=10
bar: result=60
foo: x=100 y=60
live example