c++ - 将参数转换为包装函数所需的类型

标签 c++ c++14 variadic-templates

假设我希望我有一个通用函数F,它接受Args类型的参数并返回R。我想包装此函数,使其适合以下形式:

using gen_type = void (*)(struct value *values,
                          size_t num_args,
                          struct value *return_value)
我也有与通用struct value相互转换的函数:
template<T> T from_value(struct value);
// or have something like from_value_(struct value, int&)
// called from from_value
template<> from_value<int>(struct value);
struct value to_value(int i);
现在,我可以有一个类似的功能:
template<typename F, typename ... Args>
gen_type wrap(F func) {
    return [](struct value *values,
              size_t num_args,
              struct value *return_value) {
        if (num_args != sizeof...(Args)) { /* error */ }
        auto res = func(/* apply from_value<> to each argument type */)
        *return_value = to_value(res);
    }
}
问题是,评论应放在何处。
(旁边的问题:调用wrap时有什么方法可以避免描述F的参数类型?)

最佳答案

下面是一个示例,如何使用Boost.Hanafunc作为模板参数来完成。

#include <iostream>
#include <math.h>
#include <boost/hana.hpp>

namespace hana=boost::hana;

// sample value type
struct value
{
    size_t content;
};

// sample conversion functions for sample value type

template <typename T>
T from_value(const value& val)
{
    return T(val.content);
}
template <>
int from_value<int>(const value& val)
{
    return val.content*2;
}
template <>
float from_value<float>(const value& val)
{
    return val.content*3.0;
}

template <typename T>
value to_value(const T& val)
{
    return value{static_cast<size_t>(round(val))};
}

// concatenate results of from_value to tuple

template <typename ...>
struct concat_values
{
};

template <typename T>
struct concat_values<T>
{
    template <typename ArrT>
    static auto apply(size_t index,const ArrT& arr)
    {
        return hana::make_tuple(from_value<T>(arr[index]));
    }
};

template <typename T, typename ... Types>
struct concat_values<T,Types...>
{
    template <typename ArrT>
    static auto apply(size_t index,const ArrT& arr)
    {
        return hana::prepend(concat_values<Types...>::apply(index+1,arr),
                            from_value<T>(arr[index])
                            );
    }
};

// wrap lambda
template <typename FuncT, FuncT func, typename ... Args>
auto wrap()
{
    return [](value *values,
            size_t num_args,
            value *return_value)
    {
        if (num_args != sizeof...(Args)) { throw std::runtime_error("Invalid number of arguments!"); }

        auto res=hana::unpack(
            concat_values<Args...>::apply(0,values),
            *func
        );
        *return_value = to_value(res);
    };
}

// try it

// sample func
double sample_sum(size_t a, int b, float c)
{
    return a+b*2+c*3;
}

// sample function with C-style signature that accepts wrapped function
void sample_invoke(void (*f)(value*,size_t,value*))
{
    value inputs[3]={{1},{2},{3}};
    value result{0};
    (*f)(inputs,3,&result);

    std::cout<<"Result "<<result.content<<std::endl;
}

// run
int main()
{
    auto wrapped=wrap<decltype(&sample_sum),&sample_sum,size_t,int,float>();
    sample_invoke(wrapped);
    return 0;
}
打印品:
Result 36
参见Demo
更新
另一个std::index_sequence的实现:
// apply function
template <typename ... Args, typename FuncT, std::size_t... Idx>
auto apply_func(FuncT func,value* values,std::index_sequence<Idx...>)
{
    return func(from_value<Args>(values[Idx])...);
}    

// wrap lambda
template <typename FuncT, FuncT func, typename ... Args>
auto wrap()
{
    return [](value *values,
            size_t num_args,
            value *return_value)
    {
        if (num_args != sizeof...(Args)) { throw std::runtime_error("Invalid number of arguments!"); }

        auto res=apply_func<Args...>(*func,values,std::index_sequence_for<Args...>());
        *return_value = to_value(res);
    };
}
Live Demo

关于c++ - 将参数转换为包装函数所需的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64625909/

相关文章:

c++ - Typedef 模板参数

c++ - 为什么不将字符串文字作为对数组的引用而不是不透明指针传递?

c++ - 可变参数模板和类型特征

c++ - 何时使用 weak_ptr 而不是引用调用

c++ - 类是否可以公开参数包?

c++ - 可变模板参数 : can I pick reference vs value depending on type?

c++ - 抑制警告 C4996 : why not working?

c++ - 尝试动态增加数组大小

c++ - 了解 ostream 重载

c++ - 无法在动态链接库中找到过程入口点 _ZNSt7_cxx1112basic_stringlcSt11char_traitslcESalcEEC1Ev