我想定义一个接受所有可调用对象的概念。这是我到目前为止所做的:
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 ++中的“函数”名称可能表示许多函数。它表示重载,通过模板实参推导的模板实例化等。但是要获得功能pointer
,则需要对所有内容进行对等。如果名称表示重载集,则要获取指针,必须将该名称强制转换为特定的重载。如果名称表示模板,则必须提供模板参数来表示特定的实例。意思是,当您假设的is_callable
概念在函数指针类型上被调用时,所有重载解析和模板替换已经发生。它被赋予指向特定的,定义明确的代码段的单个指针,该代码段可以使用由该指针的类型定义的签名来调用。
函数object
都不是这种情况。函子(无论是由C ++ lambda表达式生成还是仅由手写类型生成)无非就是具有operator()
重载的类型。而且,重载只是一个函数名,与任何其他名称完全一样:受重载解析和模板替换的规则约束。C ++不允许您问“这是名字;我可以用something
称呼它吗?”]从广义上讲,这不是一个有用的问题。
无论您是使用这种“可调用的”概念进行计算还是什么,在某些时候
,某些代码段都将使用带有某些参数集的函数来调用某些函数,这些参数最终将级联为调用给定的函数以及由某些过程定义的另一组参数。 这就是重点当您需要限制给定的可调用对象时。在构建可咖喱可调用对象的站点上约束功能是没有用的。您不知道参数和返回值之间是否存在类型不匹配,或任何其他类型。您只有在获得一组用于调用curried可调用对象的参数时才会知道。在这里可以计算参数以最终调用适当的函数,因此应该在此处进行约束。