如何找到模板函数的参数个数?

时间:2017-01-09 20:57:13

标签: c++ templates

我有以下类型特征:

var d = new Date('2017-02-22T22:00');
d.setMonth(d.getMonth()+1)
console.log(d);

对于大多数用例来说,查找函数所使用的参数数量非常有用,但是对于一个常见情况它会失败:

template <class T>
struct Arity : Arity<decltype(&T::operator())> {};

template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...)> {
    static constexpr auto value = sizeof...(Args);
};

template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...) const> {
    static constexpr auto value = sizeof...(Args);
};

template <class R, class... Args>
struct Arity<R(*)(Args...)>  {
    static constexpr auto value = sizeof...(Args);
};

我认为通常不能为任何模板化的函数/运算符()使其工作,因为根据作为模板类型传递的类型/值,可以选择不同的重载,或者可能没有可用的重载一点都不此外,无法知道要传递的有效类型和值作为模板参数。但是,我仍然希望这适用于lambda采用auto l1 = [](int, double){}; Arity<decltype(l1)>::value; // works, 2 auto l2 = [](auto, auto){}; Arity<decltype(l2)>::value; // error: Reference to overloaded function could not be resolved; did you mean to call it? 参数的常见情况。有没有办法让这个更强大并覆盖带有自动参数的lambda?

2 个答案:

答案 0 :(得分:4)

我想我在这里实现了一半的解决方案。仅适用于固定数量的参数,但对于大多数不应该成为问题的应用程序。此外,它可能是高度简化的,但我的大脑现在还没有陷入棘手的SFINAE。

template <
    class, std::size_t N,
    class = std::make_index_sequence<N>,
    class = void_t<>
>
struct CanCall : std::false_type { };

template <class F, std::size_t N, std::size_t... Idx>
struct CanCall<
    F, N,
    std::index_sequence<Idx...>,
    void_t<decltype(std::declval<F>()((Idx, std::declval<Any const&&>())...))>
> : std::true_type { };

CanCall<F, N>将返回F是否可以使用任意类型的N参数进行调用。 Any辅助类型具有模板化的隐式转换运算符,允许它转换为任何所需的参数类型。

template <class F, std::size_t N = 0u, class = void>
struct Arity : Arity<F, N + 1u, void> { };

template <class F, std::size_t N>
struct Arity<F, N, std::enable_if_t<CanCall<F, N>::value>>
: std::integral_constant<std::size_t, N> { };

template <class F>
struct Arity<F, MAX_ARITY_PROBING, void>
: std::integral_constant<std::size_t, ARITY_VARIADIC> { };

Arity<F>只检查是否可以使用零,一,二......参数调用F。第一次正面检查获胜。如果我们达到MAX_ARITY_PROBING个参数,Arity就会失效,并假设该函数是可变参数,或根本不是函数。

See it live on Coliru

答案 1 :(得分:2)

我认为你不能在你的参数类型为auto的用例中使用lambda函数。这些lambda函数的operator()函数很可能是使用函数模板实现的。

因此,decltype不能用于:

auto l2 = [](auto, auto){};
Arity<decltype(l2)>::value;

有关此主题的更多信息,请参阅this answer to another SO question