函子的可调用性

303*_*303 4 c++ c++20

为什么该标准不认为具有 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)

Bar*_*rry 6

这失败了:

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可以作为左值(它可以)调用,而不是作为右值(它不能)调用。