How to apply a formal protocol with C ++ templates?

When using the typical duck compilation inherent in style, is there a way to ensure that the template argument implements certain methods with specific signatures?

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();
}

Of course, even without this, there is perfect type safety: if the template argument Tdoes not have a method used to implement the template function, the compiler will always complain.

But I believe that it would be desirable to clearly state that I class Tshould have all the methods indicated in some class ProtocolT. This would allow me to limit the design earlier in the development process, requiring methods from Tthat I have not yet used in the implementation of the template function.

ProtocolT, , , , T. (, ProtocolT , , ProtocolT , , .)

+4
2

, , . ; 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();
}

, , , .

, , , .

, , . :

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();
}
+4

, 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 , g().

+2

Source: https://habr.com/ru/post/1680737/


All Articles