我想定义一个接受所有可调用对象的概念。以下是我到目前为止所做的工作:
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?
对于我正在尝试实现的目标,有没有更好的解决方案?
发布于 2020-05-07 02:57:15
你想要什么是不可能的(或者是一个好主意,但现在别管它了)。
在C++中,一个名称为"function“的函数可能代表许多函数。它表示重载、通过模板参数推导的模板实例化等。但要获得函数指针,您需要仔细查看所有这些内容。如果名称表示重载集,则要获取指针,必须将该名称强制转换为特定的重载。如果名称表示模板,则必须提供模板参数来表示特定的实例化。
这意味着,当您假设的is_callable概念在函数指针类型上被调用时,所有的重载解析和模板替换都已经发生。它被赋予一个指向特定的、定义良好的代码段的指针,可以用该指针的类型定义的签名来调用该代码段。
所有这些都不是函数对象的情况。函数器(无论是由C++λ表达式生成的,还是仅由手写类型生成的)只不过是一个带有operator()重载的类型。该重载只是一个函数名,与任何其他名称完全相同:受重载解析和模板替换规则的约束。
C++不允许您提出这样的问题:“这是一个名称;我可以用一些东西来调用它吗?”
从广义上讲,这不是一个有用的问题。
无论你是在使用这个“可调用”的概念来进行调用,还是在某个时刻,某段代码将使用某组参数调用某个函数,这最终会级联到使用某个进程定义的另一组参数调用给定的函数。这就是当你需要约束给定的可调用对象的时候。
在构建curried的地方约束函数是没有用的。你不知道参数和返回值之间是否存在类型不匹配,或者类似的东西。只有当给出一组用于调用curried可调用的参数时,您才会知道这一点。这是您可以计算参数以最终调用适当函数的地方,因此这是约束应该发生的地方。
https://stackoverflow.com/questions/61641848
复制相似问题