用c++ 20的概念实现std::is_invocable_r



我正在尝试使用c++ 20的概念实现std::is_invocable<R, Callable, Args...>,尽可能少地使用STL的帮助,而不使用std::invoke等。

这是我目前的方法。它会导致编译错误(msvc):error C3864: 'is_invocable_r': requires clause is incompatible with the declaration

template<class R, class Fn, class... ArgTypes>
requires requires(Fn fn, ArgTypes... arg_types)
{
{ std::forward<Fn>(fn)(std::forward<ArgTypes>(arg_types)...) } -> std::same_as<R>;
}
struct is_invocable_r : std::true_type {};
template<class R, class Fn, class... ArgTypes>
struct is_invocable_r : std::false_type {};

正确的做法是什么?

有两个问题

  1. 您没有对模板进行专门化。你在重新申报。部分专门化必须用模板id声明。即is_invocable_r<...>
  2. 局部专门化应该比主模板声明更约束,而不是更少。它必须是一个更特殊的情况下的主要过于参数;我们不能只是重复相同的参数列表,并称之为专门化。

考虑到这一点,定义trait的一个更简单的方法是:

template<class R, class Fn, class... ArgTypes>
struct is_invocable_r :
std::bool_constant<
requires(Fn fn, ArgTypes... arg_types)
{
{ std::forward<Fn>(fn)(std::forward<ArgTypes>(arg_types)...) } -> std::same_as<R>;
}
> 
{};

因为所有的模板形参都必须显式提供,并且没有空间专门化你的类模板(不能在类模板的形参包后面添加实参),所以我们根本不能专门化。

相反,我们只是将requires表达式的结果提供给bool_constant,因为它是表达式的结果,最终决定了特征1的值。


1-你的require表达式不包括指向成员的指针,所以它不等同于std::is_invocable_r给出的结果。需要更多的细化(甚至可能通过专门化)来覆盖这种情况。

相关内容

最新更新