【问题标题】:Clean static interface with C++20 concepts使用 C++20 概念的干净静态接口
【发布时间】:2021-05-07 04:47:19
【问题描述】:

我试图使用 C++20 概念创建一个静态接口,下面的代码似乎可以完成这项工作:

template <class FOO>
concept FooConcept = requires {
    static_cast<void (FOO::*)(int)>(&FOO::operator());
    static_cast<void (FOO::*)(char)>(&FOO::operator());
};

特别是,FOO 满足 FooConcept 类,如果此类重载 operator() 两次:分别使用 int 参数和 char 参数。

此解决方案似乎工作正常,但看起来并不美观。事实上,我更喜欢以下形式:

template <class FOO>
concept FooConcept = requires (FOO foo, int i, char c) {
    { foo(i) } -> std::same_as<void>;
    { foo(c) } -> std::same_as<void>;
};

template <class FOO>
concept FooConcept = std::invocable<FOO, int> && std::invocable<FOO, char>;

但是,由于隐式转换,这些方法不起作用(请参阅this post)。 有没有更好、更“语义化”的方式来表达这种约束?

【问题讨论】:

  • "FooConcept 满足 FOO 类当且仅当此类重载 operator() 两次:分别使用 int 参数和 char 参数。 - 不完全:如果但非仅当:如果FOO 具有模板运算符(例如template &lt;typename T&gt; void operator() (T) { })也满足
  • 当然,我的错!我会立即解决这个问题。但它仍然做我想做的事:它表现为一个静态接口!
  • 是的,它们反映了受概念约束的模板如何实际使用该类型。例如,拥有t.foo(0); 意味着模板可以安全地执行t.foo(0)。在这种情况下,是否转换 0 是无关紧要的。您可以查看 C++0x 概念历史,以了解为什么以您尝试做的方式指定接口的原始方向不是当前概念所采用的方向。这些会议和讨论的结果将比我更能说明原因。
  • 好吧,你总是可以给丑陋起个名字:godbolt.org/z/TG45c5PGe
  • @fdev,我没有引用任何特定的东西,但我知道概念的原始化身有相当的历史。对于一个大功能走向死胡同,然后以完全不同的形式回归,这涉及到大量的讨论,所以它更像是一个一般性的参考。我并没有试图大惊小怪,而是指出当前的化身旨在为类型的用户而不是实现者建模,因为心理模型完全不同。

标签: c++ c++20 concept


【解决方案1】:

使用一些帮助器,并且使用非final 类,您可能会这样做:

template <typename T>
struct DeletedOperator : T
{
    using T::operator ();

    template <typename ... Ts>
    void operator()(Ts&&...) = delete;

    template <typename ... Ts>
    void operator()(Ts&&...) const = delete;
};

template <class FOO>
concept FooConcept = requires (DeletedOperator<FOO> foo, int i, char c) {
    { foo(i) } -> std::same_as<void>;
    { foo(c) } -> std::same_as<void>;
};

Demo

我认为我们可以通过调整助手来摆脱非final 约束。

【讨论】:

  • 我赞成你的想法,虽然我不完全理解!你介意详细说明一下吗?无论如何,它不会产生完全期望的行为:例如,如果类 FOO 使用默认参数重载 operator()(例如,void operator()(int i, double d = 0.); 而不是 void operator()(int i);),那么您定义的 FooConcept 将获胜不要抱怨,而我正确建议的实施会。另外,虽然问题中没有明确说明,但我想要一种通用方法来为通用成员函数执行所有这些操作,并且不限于 operator() 函数!
  • 想法是模板删除的重载可以避免转换,因为它们是完全匹配的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 2020-12-11
  • 2021-11-27
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
相关资源
最近更新 更多