c++ - 是否可以定义一个包含函数和 lambda 的可调用概念?
问题描述
我想定义一个可以接受所有可调用对象的概念。这是我到目前为止所做的:
template<typename F>
concept Func = std::is_function_v<std::remove_pointer_t<std::decay_t<F>>> || (requires (F f) {
std::is_function_v<decltype(f.operator())>;
});
bool is_callable(Func auto&&) {
return true;
}
bool is_callable(auto&&) {
return false;
}
然而,如果我定义这些:
auto f = [](auto a, auto b, auto c, auto d, auto e) {
return a * b * c * d * e;
};
int g(int a, int b) {
return a + b;
}
is_callable(g)
是true
但是is_callable(f)
是false
,它没有用(我希望两者都返回true
)。
所以我试图看看以下是否会编译:
decltype(f.operator()) // Reference to non-static member function must be called
decltype(&f.operator()) // Cannot create a non-constant pointer to member function
decltype(f::operator()) // 'f' is not a class, namespace, or enumeration
decltype(&f::operator()) // same as previously
它给了我你可以看到的错误,作为对这 4 行的评论。
有没有办法检查 f 是否有一个有效的函子,这意味着 f 是一个 lambda?
我想要实现的目标有更好的解决方案吗?
解决方案
你想要的是不可能的(或者是一个好主意,但现在没关系)。
C++ 中按名称命名的“函数”可能代表许多函数。它通过模板参数推导表示重载、模板实例化等。但是要获得函数指针,您需要仔细查看所有这些。如果名称表示重载集,要获得指针,您必须将该名称强制转换为特定的重载。如果名称表示模板,则必须提供模板参数来表示特定的实例化。
这意味着,当您的假设is_callable
概念在函数指针类型上被调用时,所有重载决议和模板替换都已经发生。它被赋予一个指向特定的、定义良好的代码段的指针,该代码段可以使用由该指针类型定义的签名来调用。
函数对象都不是这种情况。仿函数(无论是由 C++ lambda 表达式生成还是只是手写类型)只不过是一种具有operator()
重载的类型。重载只是一个函数名,与任何其他名称完全一样:受重载解析和模板替换规则的约束。
C++ 不允许你问“这是一个名字;我可以用一些东西来称呼它吗?”
从广义上讲,这不是一个有用的问题。
无论您是使用这种“可调用”概念进行柯里化还是使用什么,在某些时候,某些代码将使用一组参数调用某个函数,最终将级联到调用具有另一组参数定义的给定函数通过一些过程。这就是您需要约束给定可调用对象的时候。
在构建 curried callable 的站点上限制函数是没有用的。您不知道参数和返回值之间是否存在类型不匹配,或者类似的情况。只有当您获得一组用于调用 curried 可调用对象的参数时,您才会知道这一点。那是您可以计算参数以最终调用正确函数的地方,因此应该进行约束。
推荐阅读
- javascript - 将views.py中的值显示为html
- python-3.x - Python3 PyTest Flask JWT 抛出 HTTP 422 Unprocessable Entity
- javascript - 使用 .join 在多个值之间返回 `|`
- excel - 如果另一个单元格返回错误,则使用 VBA 解锁一个单元格
- python - 姜戈 | 无法访问没有尾随“/”的 URL
- c++ - 如何测试 int 的文件输入?
- arrays - 范围到数组 - 根据查找值插入公式
- javascript - 使用 ajax json 在下拉列表中显示数据
- sql - SQL:如何为每个具有现有值的用户获取包含单个记录的结果集
- javascript - 为什么使用 removeEventListener 而不是只删除它?