使用 C++ 20 概念实现 std::is_invocable_r

时间:2021-07-25 17:51:50

标签: c++ c++20 c++-concepts

我正在尝试使用 C++ 20 的概念在尽可能少的 STL 帮助下实现 std::is_invocable<R, Callable, Args...>,并且不使用 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 个答案:

答案 0 :(得分:2)

两个问题。

  1. 您没有专门设计模板。您正在重新声明它。必须使用模板 ID 声明部分特化。 IE。 is_invocable_r<...>
  2. 部分特化应该比主模板声明更多约束,而不是更少。并且它必须是主参数的更特殊的情况;我们不能只是重复完全相同的参数列表并将其称为特化。

考虑到这一点,定义特征的更简单方法可能是:

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,因为它是最终决定 trait1 值的表达式的结果。< /p>


<子>

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