使用C++检测习惯用法计算任意可调用对象的参数
Counting arguments of an arbitrary callable with the C++ detection idiom
我一直在使用C++检测习惯用法创建一个元函数,用于确定任意可调用函数的参数数量。到目前为止,我在http://ideone.com/BcgDhv):
static constexpr auto max_num_args = 127;
struct any { template <typename T> operator T() { } };
template <typename F, typename... Args>
using callable_archetype = decltype( declval<F>()(declval<Args>()...) );
template <typename F, typename... Args>
using is_callable_with_args = is_detected<callable_archetype, F, Args...>;
template <typename F, size_t I = 0, typename... Args>
struct count_args
: conditional<is_callable_with_args<F, Args...>::value,
integral_constant<size_t, I>,
count_args<F, I+1, Args..., any>
>::type::type
{ };
template <typename F, typename... Args>
struct count_args<F, max_num_args, Args...> : integral_constant<size_t, max_num_args> { };
当所有可调用参数都不是左值引用时,这种方法非常有效:
void foo(int i, int j) { }
static_assert(count_args<decltype(foo)>::value == 2, "");
但是,当任何一个参数是左值引用时,这将失败(原因很明显,因为可调用原型有替换失败):
void bar(char i, bool j, double& k);
static_assert(count_args<decltype(bar)>::value == 3, "doesn't work");
有人知道如何推广这个想法,使其也适用于左值引用吗?
以下工作(针对小型max_num_args
):
struct any { template <typename T> operator T(); };
struct anyref { template <typename T> operator T&(); };
template <typename F, typename... Args>
using callable_archetype = decltype(std::declval<F>()(std::declval<Args>()...) );
template <typename F, typename... Args>
using is_callable_with_args = std::is_detected<callable_archetype, F, Args...>;
template <typename F, size_t I = 0, typename... Args>
struct count_args
: std::conditional<is_callable_with_args<F, Args...>::value,
std::integral_constant<std::size_t, I>,
std::integral_constant<std::size_t,
std::min(count_args<F, I+1, Args..., any>::value,
count_args<F, I+1, Args..., anyref>::value)>
>::type::type
{};
template <typename F, typename... Args>
struct count_args<F, max_num_args, Args...> :
std::integral_constant<std::size_t, max_num_args> {};
演示
但是代码必须进行优化,因为复杂性是2**max_num_args
:/
更改此行:
struct any { template <typename T> operator T() { } };
至:
struct any {
template <typename T> operator T&&() { }
template <typename T> operator T&() { }
};
实例
我们有一个左值和右值隐式强制转换运算符。所以,我们。。。好的
在@Jarod42的答案的基础上,对any
的一个稍微好一点的定义似乎在绝大多数情况下都能奏效(不包括由于其他原因导致callable_archetype
成为替换错误的情况;例如,具有已删除的复制构造函数的类,其调用无论如何都无效):
struct any {
template <typename T,
typename = enable_if_t<
not is_same<T, remove_reference_t<T>>::value
>
>
operator T();
template <typename T,
typename = enable_if_t<
is_same<T, remove_reference_t<T>>::value
>
>
operator T&();
template <typename T,
typename = enable_if_t<
is_same<T, remove_reference_t<T>>::value
>
>
operator T&&();
};
在没有指数缩放的情况下,这似乎在与前面的答案相同的所有情况下都有效。
演示
相关文章:
- 是什么让放置新调用对象的构造函数?
- 当我调用对象的方法时,对象的成员会发生变化
- 为什么静态数组成员变量在调用对象的实例后不显示任何内容?
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 如何从构造函数副本 T(const T&)调用对象 T?
- C++17 如何保存泛型可调用对象以供以后使用
- 检查模板中 nullptr 的函数指针,了解任何类型的可调用对象
- 是否可以在编译时初始化对象的 C 样式函数指针,以便它调用对象的成员函数?
- 如何在C++中将可调用对象放入地图中?
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 广义 std::function (std::any 表示可调用对象)
- c++ 替换调用对象方法的宏函数
- 将可调用对象传递给采用 std::function 的构造函数
- 双指针在使用 new 时不调用对象构造函数
- 可调用对象作为默认模板参数
- 只需调用对象即可获取对象数据
- 如果用户尝试从 JS 调用对象的未定义函数C++则回调C++代码
- 如何将当前替代类型的 std::variant 传递给可调用对象?
- C++对象本身作为参数调用对象的方法
- 从移交的类调用对象