【问题标题】:Dynamically creating and expanding std::tuple into parameter pack动态创建 std::tuple 并将其扩展为参数包
【发布时间】:2017-06-06 15:28:58
【问题描述】:

我正在为用 C++ 编写的软件编写一个插件,这是一个定义插件的 sn-p:

extern "C"
irods::ms_table_entry* plugin_factory() {

    // The number of msParam_t* arguments that it will accept
    int numArguments = 2;

    irods::ms_table_entry* msvc = new irods::ms_table_entry(numArguments); 

    msvc->add_operation(
        "my_microservice",
        std::function<int(msParam_t*, msParam_t*, ruleExecInfo_t*)>(MyMicroservice)
    ); 

    return msvc;
}  

我希望能够使用numArguments 动态生成std::function&lt;int(msParam_t*, msParam_t*, ruleExecInfo_t*)&gt; 参数包。其中numArguments 表示msParam_t* 参数的数量。

我不是 C++ 专家(尤其是模板方面),所以after some research 我发现这可能可以通过实现以下内容来实现:

  • std::tuple
  • std::tuple_cat
  • std::index_sequence
  • std::make_integer_sequence

但我真的不知道如何开始实施这一点。我发现的例子很难理解,我无法将它们转化为我自己的需求。任何人都可以提供有关这可能如何工作的提示、简短示例或参考吗?非常感谢任何信息!

【问题讨论】:

  • 在编译时是否知道numArgument
  • 不可能动态地执行此操作,因为这将涉及代码生成,但您可以静态生成它或静态生成它。 add_operation 的类型是什么?
  • @DavideSpataro - 不,numArgument 将在运行时定义。
  • 是否代表MyMicroservice的参数个数?如果确实如此,则在编译时就知道了。
  • 你不能在运行时做一些应该在编译时已经完成的事情...std::make_index_sequence 需要在编译时知道的参数在那个时候生成适当的 std::integer_sequence 如果你在编译时不知道值你注定要创建你希望支持的所有可能的选项,然后在运行时从以前预编译的类型中选择一个......

标签: c++ c++11 variadic


【解决方案1】:

我不知道以下是否正是您要问的,但我认为您想要的是能够根据您的 MyMicroservice 的参数数量为 std::function 生成正确的模板参数将其存储到numParameters 变量中。

如果是这种情况,您可以完全省略编写它们并使用 decltype 并让编译器为您编写它们。

int myMicroservice1(int a,int b, int c){
    return a+b+c;
}

int myMicroservice2(int a,int b, int c,int d){
    return a*b*c-d;
}

int myMicroservice3(int a,int b, int c,int d,int e, int f){
    return a*b*c+e+f;
}


template<typename... types_t>
void add_operation(const std::string & _op, std::function< int(types_t...)> _f ){

}   

int main() {
    add_operation("blabla",std::function<decltype(myMicroservice1)>(myMicroservice1));
    add_operation("blabla",std::function<decltype(myMicroservice2)>(myMicroservice2));
    add_operation("blabla",std::function<decltype(myMicroservice3)>(myMicroservice3));
    return 0;
}

【讨论】:

  • 我刚刚意识到,即使我可以从运行时整数动态构建参数包,MyMicroservice 参数仍然是静态的。需要为每组不同的参数定义一个函数。感谢您的回答,它帮助我发现了我的想法中的缺陷。
【解决方案2】:
template<typename T>
struct toFunc;

template<typename...T>
struct toFunc<std::tuple<T...>>
{
    using type = std::function<void(T...)>;
};

int main(int argc, char **argv) {

    using t = std::tuple<int, int, int>;
    using func = toFunc<t>::type;
    auto f = func([](int a, int b, int c){std::cout << a << b << c << std::endl;});
    f(1, 2, 3);
  return 0;
}

toFunc typetrait 会将您的元组转换为函数类型。不知道你是否想要那个。如果你想用参数调用,你可能需要寻找 http://en.cppreference.com/w/cpp/utility/apply

或者你可以使用这个实现:

namespace detail
{
            template <unsigned int N>
            struct for_each_t_idx
            {
                template <template<std::size_t> class Functor, typename... ArgsT>
                static void exec(const std::tuple<ArgsT...>& t, Functor<N> func)
                {
                    for_each_t_idx<N - 1>::exec(t, func);
                    func<N - 1>(t);
                }
            };

            template <>
            struct for_each_t_idx<0>
            {
                template <template<std::size_t> class Functor, typename... ArgsT>
                static void exec(const std::tuple<ArgsT...>& t, Functor<0> func)
                {
                }
            };
}

    template <template<std::size_t> class Functor, typename... ArgsT>
    void for_each_idx(const std::tuple<ArgsT...>& t, Functor<sizeof...(ArgsT)> func)
    {
        detail::for_each_t_idx<sizeof...(ArgsT)>::exec(t, func);
    }

这将为元组中的每个元素调用一个给定的函数。

【讨论】:

    猜你喜欢
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 2020-04-07
    相关资源
    最近更新 更多