3

my questions are in the following code:

template <class _type>
_type translateArgument (std::string);

template <class _type>
std::string translateResult (_type result);

template <class _function_type, _function_type _function, class _result_type, class... _arguments_type>
struct Function
{
    typedef std::tuple<_arguments_type...> arguments_type;

    static void call(std::stack<std::string> stack)
    {
        auto value1 = translateArgument<std::tuple_element<0, arguments_type>::type>(stack.top());
        stack.pop();

        auto value2 = translateArgument<std::tuple_element<1, arguments_type>::type>(stack.top());
        stack.pop();

        ...
    }
};

1.first question :

how to generate code from value1 to valueN, where N is the sizeof...(_arguments_type)

2.second question :

if _result_type is void, add code to the end of Function::call

_function(value1, value2, ...);

otherwise, add code to the end of Function::call

stack.push(translateResult<_result_type>(_function(valu1, value2, ...)));
m.s.
  • 16,063
  • 7
  • 53
  • 88
J.Doe
  • 130
  • 1
  • 7
  • You cannot have anything other than types (including pointers and references and built-in types such as int, float, etc.), other template types and integral constant expressions as template parameter to `struct Function`. – a_pradhan Oct 27 '15 at 07:43

2 Answers2

1
template <typename F, F function, typename R, typename... Args>
struct Function
{
    using arguments_type = std::tuple<Args...>;

    static void call(std::stack<std::string>& stack)
    {
        call_n(std::is_void<R>{}, stack, std::index_sequence_for<Args...>{});
    }

    template <std::size_t I>
    static typename std::tuple_element<I, arguments_type>::type f(std::stack<std::string>& stack)
    {
        typename std::tuple_element<I, arguments_type>::type e{ translateArgument<typename std::tuple_element<I, arguments_type>::type>(stack.top()) };
        stack.pop();
        return e;
    }

    template <std::size_t... Is>
    static void call_n(std::true_type, std::stack<std::string>& stack, std::index_sequence<Is...>)
    {
        std::tuple<Args...> tpl{ f<Is>(stack)... };
        function(std::get<Is>(std::move(tpl))...);
    }

    template <std::size_t... Is>
    static void call_n(std::false_type, std::stack<std::string>& stack, std::index_sequence<Is...>)
    {
        std::tuple<Args...> tpl{ f<Is>(stack)... };
        stack.push(processResult(function(std::get<Is>(std::move(tpl))...)));
    }
};

DEMO

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • Is the order in which `f(stack)` is called (from `call_n()`) 1) well-defined and 2) correctly implemented by all compilers? (I vaguely recall that some compiler gets that wrong). – Walter Oct 27 '15 at 08:45
  • @Walter with a braced-init-list you are guaranteed a left-to-right evaluation. the only well-known compiler that doesn't implement this (for a constructor call) is MSVC – Piotr Skotnicki Oct 27 '15 at 08:50
1

The following code uses the indices trick twice in order to:

  1. convert the string arguments to the respective type
  2. 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

Community
  • 1
  • 1
m.s.
  • 16,063
  • 7
  • 53
  • 88