为什么该标准不认为具有 ref 限定调用运算符的函子是可调用的?
#include <concepts>
struct f { auto operator()() {} };
struct fr { auto operator()() & {} };
struct fcr { auto operator()() const& {} };
struct frr { auto operator()() && {} };
static_assert(std::copy_constructible<f>); // ok
static_assert(std::copy_constructible<fr>); // ok
static_assert(std::copy_constructible<fcr>); // ok
static_assert(std::copy_constructible<frr>); // ok
static_assert(std::invocable<f>); // ok
static_assert(std::invocable<fr>); // fails
static_assert(std::invocable<fcr>); // ok
static_assert(std::invocable<frr>); // ok
Run Code Online (Sandbox Code Playgroud)
好吧,它可能与返回临时对象有关std::declval,我不认为这样的实现细节应该与用户相关。从语义上讲,示例代码中的函子在可调用性方面不应被视为不同。
std::invocable另外,为什么什么和std::function认为是一个对象之间似乎存在这种矛盾callable?
#include <functional>
using tf = decltype(std::function{f{}}); // ok
using tfr = decltype(std::function{fr{}}); // ok
using tfcr = decltype(std::function{fcr{}}); // ok
using tfrr = decltype(std::function{frr{}}); // fails
Run Code Online (Sandbox Code Playgroud)
更进一步的是,MVSC v19.32 似乎也接受以下代码。这只是 MSVC 的编译器错误吗?
template<std::invocable F>
auto g() -> void {}
using tg = decltype(g<f>); // ok
using tgr = decltype(g<fr>); // ok
using tgcr = decltype(g<fcr>); // ok
using tgrr = decltype(g<frr>); // ok
Run Code Online (Sandbox Code Playgroud)
这失败了:
static_assert(std::invocable<fr>); // fails
Run Code Online (Sandbox Code Playgroud)
因为它正在测试表达式的有效性std::invoke(std::declval<fr>()),该表达式试图调用类型的右值fr。但是fr的调用运算符是&- 限定的,这意味着您只能在左值上调用它。这就是它被拒绝的原因。
为什么该标准不认为具有 ref 限定调用运算符的函子是可调用的?
这并不是说它不认为它们是可调用的,期间。这就是价值类别也在其中发挥着作用std::invocable。如果您尝试过,您会发现:
static_assert(std::invocable<fr&>); // ok
Run Code Online (Sandbox Code Playgroud)
这是因为现在我们正在测试是否fr可以作为左值(它可以)调用,而不是作为右值(它不能)调用。