用于生成函数的模板,用于从运行时堆栈调用带有参数的函数

时间:2015-10-27 07:27:50

标签: c++ templates c++11

我的问题在以下代码中:

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.第一个问题:

如何从value1到valueN生成代码,其中N是sizeof ...(_ arguments_type)

2.第二个问题:

如果_result_type为void,则将代码添加到Function :: call

的末尾
_function(value1, value2, ...);

否则,将代码添加到Function :: call

的末尾
stack.push(translateResult<_result_type>(_function(valu1, value2, ...)));

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

以下代码使用indices trick两次以便:

  1. 将字符串参数转换为相应的类型
  2. 使用转换的参数调用所需的函数。
  3. 代码使用C ++ 14中的std::integer_sequence,但如果需要,可以很容易地将其转换为C ++ 11。

    #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);
        }
    };
    

    <强>演示:

    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;
    }
    

    <强>输出:

    bar: x=30 y=20 z=10
    bar: result=60
    foo: x=100 y=60
    

    live example