我们如何测试某种类型的表达式是否可以用纯右值调用?

How do we test if an expression of a certain type can be invoked with a prvalue?

使用 we have fancy new is_invocable 和花哨的新纯右值,它们并不是真正的值。

这允许您创建一个对象,而不必首先逻辑构造它,然后省略构造。

我 运行 遇到了一个问题,其中使用 std::is_invocable 来测试你是否可以调用某些东西,而 prvalue 规则似乎发生了冲突:

struct no_move {
  no_move(no_move&&)=delete;
  explicit no_move(int) {}
};
void f( no_move ) {}

现在我们可以问是否可以使用 no_move 类型的纯右值来调用 f

f( no_move(1) )

std::is_invocable< decltype(&f), no_move > 不起作用,因为它使用 std::declval<no_move>() 这是一个像 no_move&& 这样的 xvalue 而不是 no_move.

类型的纯右值

中是一样的,但是有保证的省略使得一些函数可以用 xvalue 调用(即“T&&”),而其他函数可以用 T 类型的 prvalues 调用。 =28=]

是否有替代方案,或者我们是否必须发明自己的特征来处理这种情况?

(在 std::declval<T> 返回 T 而不是 T&& 的理论世界中,我相信 is_invocable 会做正确的事情)。

您误用了 Invocable 概念。这个概念无非就是能够在给定函数和提供的参数上使用 std::invoke

你不能这样做 std::invoke(f, no_move(1)),因为这会引起转发参数的 copy/move。不可能通过像 invoke 这样的转发调用将纯右值用作参数。您可以将纯右值传递给转发调用,但对给定函数的最终调用将获得一个 xvalue。

这是避免在函数中使用固定类型作为值参数的一个很好的理由。取而代之的是 const&

C++ 没有类型特征来查看是否可以按照您想要的方式使用特定参数调用函数。

Is there an alternative, or do we have to invent our own trait to handle this case?

是的,您只需要编写不使用 declval 的自己的特征。假设你身边有 std::is_detected(我知道你确实有):

template <typename T> T make();

template <typename F, typename... Args>
using invoke_result_t = decltype(std::declval<F>()(make<Args>()...));
//                               ^^^^^^^^^^^^^     ^^^^^

template <typename F, typename... Args>
using is_invocable = std::is_detected<invoke_result_t, F, Args...>;

这样,std::is_invocable<decltype(f), no_move>就是false_type,而is_invocable<decltype(f), no_move)>就是true_type

我特意使用 declval<F>() 作为函数而不是 make 以允许在此处使用 decltype(f)。确实,invoke_result_t 应该更复杂,"do the right thing" 用于指向成员的指针等。但这至少是一个简单的近似值,表明这种方法的可行性。