我有以下类型特征:
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);
};
Run Code Online (Sandbox Code Playgroud)
对于大多数用例来说,找到函数所使用的参数数量非常有用,但是对于一个常见情况它会失败:
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?
Run Code Online (Sandbox Code Playgroud)
我认为通常不能对任何模板化的函数/运算符()进行这项工作,因为根据作为模板类型传递的类型/值,可以选择不同的重载,或者根本不可能有任何重载.此外,无法知道要传递的有效类型和值作为模板参数.但是,我仍然希望这适用于lambda参与的常见情况auto.有没有办法让这个更强大并覆盖带有自动参数的lambda?
我想我在这里已经实现了一半的解决方案。仅适用于固定数量的参数,但对于大多数应用程序来说这不应该成为问题。另外,它可能非常简单,但我的大脑现在不喜欢棘手的 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 { };
Run Code Online (Sandbox Code Playgroud)
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> { };
Run Code Online (Sandbox Code Playgroud)
Arity<F>只是检查是否F可以使用零、一、两个...参数来调用。第一个正面检查获胜。如果我们到达MAX_ARITY_PROBING参数,Arity则退出并假设该函数是可变参数,或者根本不是函数。
| 归档时间: |
|
| 查看次数: |
215 次 |
| 最近记录: |