Lambda函数,在编译时确定参数的数量

时间:2014-05-12 18:06:03

标签: c++ templates c++11 lambda c++14

我想声明一个具有N个参数的lambda函数,其中N是模板参数。有点像...

template <int N>
class A {
    std::function<void (double, ..., double)> func;
                        // exactly n inputs
};

我想不出用元函数范式来做这件事的方法。

4 个答案:

答案 0 :(得分:15)

您可以使用嵌套的typedef n_ary_function编写模板type。此类型可以使用如下:

template <int N>
class A {
    typename n_ary_function<N, double>::type func;
};

以下代码片段包含n_ary_function

的定义
template <std::size_t N, typename Type, typename ...Types>
struct n_ary_function
{
    using type = typename n_ary_function<N - 1, Type, Type, Types...>::type;
};

template <typename Type, typename ...Types>
struct n_ary_function<0, Type, Types...>
{
    using type = std::function<void(Types...)>;
};

答案 1 :(得分:3)

采用模板,计数和类型的元template,并使用N类型的副本调用模板:

template<template<class...>class target, unsigned N, class T, class... Ts>
struct repeat_type_N: repeat_type_N<target, N-1, T, T, Ts...> {};
template<template<class...>class target, class T, class... Ts>
struct repeat_type_N<target, 0, T, Ts...> {
  typedef target<Ts...> type;
};
template<template<class...>class target, unsigned N, class T>
using repeat_type_N_times = typename repeat_type_N<target, N, T>::type;

现在,我们使用它:

template<typename... Ts> using operation=void(Ts...);
template<unsigned N, class T> using N_ary_op = repeat_type_N_times< operation, N, T >;
template<unsigned N> using N_double_func = N_ary_op<N,double>;

我们测试它:

void three_doubles(double, double, double) {}

int main() {
  N_double_func<3>* ptr = three_doubles;
  std::function< N_double_func<3> > f = three_doubles;
}

并赢了。

您使用double, double, double的具体内容完全取决于您在上述系统中的用途。例如,您可以使用初始化std::function的lambda。

您可以将double, double, double打包到template<class...>struct type_list{};中,这样您就可以将其作为一个参数传递给另一个template,然后专门解压缩它。

repeat_type对大型N的递归较少:

// package for types.  The typedef saves characters later, and is a common pattern in my packages:
template<class...>struct types{typedef types type;};

// Takes a target and a `types`, and applies it.  Note that the base has no implementation
// which leads to errors if you pass a non-`types<>` as the second argument:
template<template<class...>class target, class types> struct apply_types;
template<template<class...>class target, class... Ts>
struct apply_types<target, types<Ts...>>{
  typedef target<Ts...> type;
};
// alias boilerplate:
template<template<class...>class target, class types>
using apply_types_t=typename apply_types<target,types>::type;

// divide and conquer, recursively:
template<unsigned N, class T, class Types=types<>> struct make_types:make_types<
  (N+1)/2, T, typename make_types<N/2, T, Types>::type
> {};

// terminate recursion at 0 and 1:
template<class T, class... Types> struct make_types<1, T, types<Types...>>:types<T,Types...> {};
template<class T, class Types> struct make_types<0, T, Types>:Types{};

// alias boilerplate:
template<unsigned N, class T>
using make_types_t=typename make_types<N,T>::type;

// all of the above reduces `repeat_type_N_t` to a one-liner:    
template<template<class...>class target, unsigned N, class T>
using repeat_type_N_times = apply_types_t<target, make_types_t<N,T>>;

对于大型N,上述内容可以显着减少编译时间,并处理溢出template堆栈。

答案 2 :(得分:1)

你不能直接这样做。

可以做这样的事情

template <unsigned N> class UniformTuple;

template <>
class UniformTuple <0>
{
};

template <unsigned N>
class UniformTuple : public UniformTuple <N-1>
{
public:

    template <typename... Args>
    UniformTuple (double arg, Args... args)
    : UniformTuple <N-1> (args...)
    , m_value (arg)
    {
    }

private:

    double m_value;
};

template <int N>
class A
{
    std :: function <void (const UniformTuple <N> &)> func;
};

答案 3 :(得分:0)

出于完整性考虑,以下是不递归的解决方案:

print(g.name, g.health)

See it live on Coliru