【问题标题】:Implementing std::is_invocable_r with C++ 20 concepts使用 C++ 20 概念实现 std::is_invocable_r
【发布时间】:2021-07-25 17:51:50
【问题描述】:

我正在尝试使用 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 {};

这样做的正确方法是什么?

【问题讨论】:

  • same&lt;R&gt; 是什么?
  • 相当于std::same_as,我已经更新了代码。
  • "不使用 std::invoke 等" 这是一个矛盾。 invocable 需要 std::invoke 存在。它基于 std::invoke。此外,您不应该重新实现这样的概念。标准库提供概念是有原因的。
  • 我从不认为应该这样做。我这样做是为了学习。话虽如此,我不想要像 requires(...) { std::invoke(...) } -&gt; R 这样的简单实现,这就是为什么我明确表示我不希望使用它。

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


【解决方案1】:

两个问题。

  1. 您没有专门化模板。您正在重新声明它。必须使用模板 ID 声明部分特化。 IE。 is_invocable_r&lt;...&gt;
  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,因为最终决定特征值的是表达式的结果1


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-11
    • 2021-03-04
    • 2020-09-03
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2018-05-31
    相关资源
    最近更新 更多