【问题标题】:How to enforce a formal protocol with C++ templates?如何使用 C++ 模板强制执行正式协议?
【发布时间】:2017-07-04 18:28:55
【问题描述】:

当使用 template style 固有的编译时鸭子类型时,有没有办法强制要求模板参数实现具有特定签名的特定方法?

struct ProtocolT {
  void g() const;
  void h();
}

// I want the compiler to check that T conforms to ProtocolT
// that is, T must implement g() and h() rather than just g()
template <typename T>
void f(const T& x) {
  x.g();
}

当然,即使没有这个,也有完美的类型安全性:如果模板参数T没有在模板函数实现中使用的方法,编译器总是会报错。

但我发现明确指出class T 必须具有某些class ProtocolT 中指定的所有方法很有吸引力。通过要求 T 中我尚未在模板函数实现中使用的方法,这将允许我在开发过程的早期约束设计。

即使我没有在ProtocolT 中包含任何未使用的方法,我仍然认为当我需要编写一个可用作T 的类时,经过验证的协议一致性会有所帮助。 (当然,没有人阻止我写 ProtocolT 用于文档目的,但是编译器不会验证 ProtocolT 至少包含所有必需的方法。)

【问题讨论】:

标签: c++ templates generic-programming type-constraints


【解决方案1】:

您正在寻找的功能称为concepts。它们目前是技术规范; GCC 有一个概念 lite 的实现。

使用概念看起来像(我对语法不太熟悉,所以可能会略有不同):

template <typename T>
concept bool Protocol = requires(const T a, T b) {
  { a.g() } -> void;
  { b.h() } -> void;
};

void f(const Protocol& x) {
  x.g();
}

但是,如果您想要一个可以立即使用的解决方案,您可以使用各种技术来模拟概念。

您可以编写类型特征来检测函数是否执行您想要的操作。

您还可以使用detection idiom,它抽象了以前的技术,大大减少了样板。以您为例:

template <typename T>
using g_t = decltype(std::declval<const T&>().g());

template <typename T>
using h_t = decltype(std::declval<T&>().h());

template <typename T>
constexpr bool meets_protocol_v = std::experimental::is_detected_exact_v<void, g_t, T>
            && std::experimental::is_detected_exact_v<void, h_t, T>;

在使用它时,您既可以对 SFINAE 友好并且 SFINAE 脱离 meets_protocol_v,也可以静态断言:

template <typename T>
void f(const T& x) {
  static_assert(meets_protocol_v<T>, "Doesn't meet protocol");
  x.g();
}

【讨论】:

    【解决方案2】:

    可能插入对应的static_assert:

    static_assert
    (
        ::std::is_same< void, decltype(::std::declval< T >().h()) >::value
    ,   "T must implement void h(void)"
    );
    

    还请注意,在您的示例中,当 T 遵循 ProtocolT 要求时,它仍然无法工作,因为 f 接受 const 对 T 的引用,而 ProtocolT 仅表示它应该具有非 const g() .

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-21
      • 2012-11-18
      • 2016-09-04
      • 2016-03-14
      • 2019-12-17
      • 1970-01-01
      相关资源
      最近更新 更多