我们如何测试是否可以使用prvalue调用某个类型的表达式?

Yak*_*ont 15 c++ c++17 prvalue declval invocable

使用我们看到了新的is_invocable和花哨的新prvalues,它们并不是真正的价值.

这允许您创建一个对象而无需首先在逻辑上构造它,然后忽略构造.

我遇到了一个问题,std::is_invocable用于测试你是否可以调用某些内容,而prvalue规则似乎会发生冲突:

struct no_move {
  no_move(no_move&&)=delete;
  explicit no_move(int) {}
};
void f( no_move ) {}
Run Code Online (Sandbox Code Playgroud)

现在我们可以问一下是否f可以使用类型的prvalue调用no_move

f( no_move(1) )
Run Code Online (Sandbox Code Playgroud)

std::is_invocable< decltype(&f), no_move >不起作用,因为它使用的std::declval<no_move>()是xvalue,no_move&&而不是类型的prvalue no_move.

这是相同的,但保证省略使得一些函数可以用xvalue(即" T&&")调用,而其他函数可以用prvalues类型调用T.

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

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

Nic*_*las 6

您滥用Invocable概念.这个概念仅仅意味着std::invoke在给定函数和提供的参数上使用的能力.

你做不到std::invoke(f, no_move(1)),因为这会激发转发参数的复制/移动.通过转发调用将prvalue用作参数是不可能的invoke.您可以将prvalue传递给转发调用,但最终调用给定函数将获得xvalue.

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

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


Bar*_*rry 3

是否有其他选择,或者我们是否必须发明自己的特征来处理这种情况?

是的,你只需要编写自己的不使用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...>;
Run Code Online (Sandbox Code Playgroud)

这样,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应该更复杂,并且对于指向成员的指针等“做正确的事情”。但这至少是一个简单的近似值,表明了这种方法的可行性。

  • @TC也许你有一个函数模板,它接受一个可调用函数,并且主体用纯右值调用它?这可能会发生。 (2认同)
  • @NicolBolas那是因为“std::invoke()”是解决问题的错误方法,我们应该通过实际使指向成员的指针可调用来使它们可调用。我试过。 (2认同)