根据模板参数改变函数的参数列表?

时间:2014-11-07 23:02:45

标签: c++ templates c++11 boost template-meta-programming

我正在尝试创建一个模板类,该类使用类型为 C 的参数执行用户指定的 N -ary函数。为此,我需要一些方法来根据模板参数指定此函数的类型。以下代码说明了我的问题:

template <typename C, size_t N>
class NaryDispatch {

    typedef typename std::function<void(/* N parameters of type C& */)> NaryFn;

    public:
        NaryDispatch(NaryFn f) : m_function(std::forward<NaryFn>(f)) {}

    private:
        NaryFn m_function;
};

我一直无法找到一种方法来构建具有适当arity签名的std :: function类型。我正在广泛使用C ++ 11和Boost :: MPL,因此非常受欢迎。我试图在构造函数参数上使用SFINAE /模板参数推导,如下所示:

template <
    class... Args,
    typename std::enable_if<sizeof...(Args) == N, C>::type = 0
>
NaryDispatch(std::function<void(Args&...)> fn) : m_function(std::forward<???>(fn)) {}

正如您所看到的,问题在于,由于模板参数 C N ,我无法确定函数将采用的类型,I' m无法确定应存储函数的类成员的类型。

为了简化我的意图,对于模板参数 C N ,类构造函数应该接受(并存储在私有成员中)std::function返回void并接受C&类型的 N 参数。例如,以下应编译:

NaryDispatch<int, 3> disp([](int a, int b, int c) {});

提前感谢您提供的任何见解。

2 个答案:

答案 0 :(得分:4)

这不应该太难。让我们从顶级开始:

template <typename C, std::size_t N>
struct NaryDispatch
{
    // details, see below

    using f_type = typename function_maker<C &, N>::type;

    template <typename F>
    NaryDispatch(F && f) : fn_(std::forward<F>(f)) {}

    f_type fn_;
};

现在我们只需要实现特征function_maker

template <typename T, std::size_t K, typename ...Args>
struct function_maker
{
    using type = typename function_maker<T, K - 1, T, Args...>::type;
};

template <typename T, typename ...Args>
struct function_maker<T, 0, Args...>
{
    using type = std::function<void(Args...)>;
};

最后,您可能还想提供某种约束调用函数。也许是这样的:

template <typename ...Args,
          typename = typename std::enable_if<sizeof...(Args) == N>::type>
void run(Args &&... args)
{
    fn_(std::forward<Args>(args)...);
}

答案 1 :(得分:0)

您的下一个问题是“如何将N个参数传递给包含的std::function?”我认为通过使用适用于任何旧参数类型列表的调度程序类模板,您可以大大简化:

template <typename...Args>
class Dispatcher {
    typedef typename std::function<void(Args...)> Fn;

    public:
        Dispatcher(Fn f) : m_function(std::move(f)) {}

        void operator()(Args...args) {
          m_function(std::forward<Args>(args)...);
        }

    private:
        Fn m_function;
};

以及一些元编程来计算正确的Dispatcher特化以处理C&类型的N个参数:

template <typename C, size_t N, typename...Args>
struct NaryDispatch_ {
  using type = typename NaryDispatch_<C, N-1, Args..., C&>::type;
};
template <typename C, typename...Args>
struct NaryDispatch_<C, 0, Args...> {
  using type = Dispatcher<Args...>;
};

template <typename C, size_t N>
using NaryDispatch = typename NaryDispatch_<C, N>::type;

<强> DEMO AT IDEONE