使用std :: apply进行实验调度

时间:2017-06-01 12:31:20

标签: c++

我想要一个通用的功能'请求'它可以接受任意数量参数的元组。我想要'请求'函数将调用分配给许多其他函数,具体取决于参数的数量(当然函数的接口必须匹配)。

我编写了这段代码,但只有当我在“请求”中调用一种类型的函数时它才有效。一旦我取消对调度机制的注释(否则 - >> dispatch到fun5),一切都停止编译。

问题在于,为调度带有两个参数的函数而创建的函数体'必须编译,然后在其中有一个带有5个参数的函数,其中无法应用2个参数的元组。反之亦然。模板的经典问题。我知道我可以以某种方式将SFINAE概念应用于这个问题,但我不知道如何(我在MPL编程中不那么强大)。

#include <iostream>
#include <experimental/tuple>

enum class type { v2, v5 };

void fun2(int i1, int i2)
{
    std::cout << "fun2 called, i1 = " << i1 << ", i2 = " << i2 << std::endl;
}

void fun5(bool b1, float f1, int i, char c, bool b2)
{
    std::cout << "fun5 called with: " << std::boolalpha << b1 << ", " << f1 << ", " << i << ", " << c << ", " << b2 << std::endl;
}

template <typename F, typename... T>
void dispatch(F f, T... args)
{
    std::experimental::apply(f, args...);    
}

template <typename... T>
void request(type t, T... args)
{
    if (t == type::v2)
      dispatch(fun2, args...);
    // else
    //  dispatch(fun5, args...);
}

int main()
{
   auto v2 = std::make_tuple(1,1);
   request(type::v2, v2);

  // auto v5 = std::make_tuple(true, 1.5f, 3, 'c', false);
  // request(type::v5, v5);   
}

我该如何使这项工作?我需要什么样的调度机制来完成这项工作?

2 个答案:

答案 0 :(得分:1)

我建议您使用标记和标记结构,而不是使用枚举来选择要执行的操作。然后,您只需使用简单的函数重载选择正确的dispatch函数。

也许像

namespace type
{
    struct v2_tag {};
    struct v5_tag {};

    v2_tag v2;
    v5_tag v5;
}

template<typename... T>
void request(type::v2_tag, T... args)
{
    dispatch(fun2, args...);
}

template<typename... T>
void request(type::v5_tag, T... args)
{
    dispatch(fun5, args...);
}

其余代码保持不变。

答案 1 :(得分:0)

标记调度的替代方法(我强烈建议as per @Some programmer dude)将创建您自己的函数对象,该对象接受type作为非类型模板参数,以便我们可以利用{ {3}}:

template<type t>
struct request
{
    template<class... T>
    void operator()(T... args) const
    {
        if constexpr(t == type::v2)
            dispatch(fun2, args...);
        else
            dispatch(fun5, args...);
    }
};

缺点是你必须构建一个来打电话:

auto v2 = std::make_tuple(1, 1);
request<type::v2>()(v2);

auto v5 = std::make_tuple(true, 1.5f, 3, 'c', false);
request<type::v5>()(v5); 

constexpr if

此方法的一个变体是在static类中使用apply request函数,如下所示:

template<type t>
struct request{
  template<class... T>
  static void apply(T... args){/*..*/}
}

然后对它的调用将会是这样的(没有时髦的空括号):

request<type::v2>::apply(v2);

Demo