Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <type_traits>
7 :
8 : #include "Utilities/TypeTraits.hpp"
9 :
10 : namespace tt {
11 :
12 : /*!
13 : * \ingroup ProtocolsGroup
14 : * \brief Indicate a class conforms to the `Protocol`.
15 : *
16 : * (Publicly) inherit classes from this class to indicate they conform to the
17 : * `Protocol`.
18 : *
19 : * \see Documentation on \ref protocols
20 : */
21 : template <typename Protocol>
22 1 : struct ConformsTo {};
23 :
24 : // Note that std::is_convertible is used in the following type aliases as it
25 : // will not match private base classes (unlike std::is_base_of)
26 :
27 : /// @{
28 : /*!
29 : * \ingroup ProtocolsGroup
30 : * \brief Checks if the `ConformingType` conforms to the `Protocol`.
31 : *
32 : * This metafunction is SFINAE-friendly. See `tt::assert_conforms_to` for a
33 : * metafunction that is not SFINAE-friendly but that triggers static asserts
34 : * with diagnostic messages to understand why the `ConformingType` does not
35 : * conform to the `Protocol`.
36 : *
37 : * This metafunction only checks if the class derives off the protocol to reduce
38 : * compile time. Protocol conformance is tested rigorously in the unit tests
39 : * instead.
40 : *
41 : * \see Documentation on \ref protocols
42 : * \see tt::assert_conforms_to
43 : */
44 : template <typename ConformingType, typename Protocol>
45 1 : struct conforms_to
46 : : std::is_convertible<ConformingType*, ConformsTo<Protocol>*> {};
47 : template <typename ConformingType, typename Protocol>
48 0 : constexpr bool conforms_to_v = conforms_to<ConformingType, Protocol>::value;
49 : /// @}
50 :
51 : /// @{
52 : /*!
53 : * \ingroup ProtocolsGroup
54 : * \brief Assert that the `ConformingType` conforms to the `Protocol`.
55 : *
56 : * Similar to `tt::conforms_to`, but not SFINAE-friendly. Instead, triggers
57 : * static asserts with diagnostic messages to understand why the
58 : * `ConformingType` fails to conform to the `Protocol`.
59 : *
60 : * \see Documentation on \ref protocols
61 : * \see tt::conforms_to
62 : */
63 : template <typename ConformingType, typename Protocol>
64 1 : struct assert_conforms_to : std::true_type {
65 : static_assert(
66 : tt::conforms_to_v<ConformingType, Protocol>,
67 : "The type does not indicate it conforms to the protocol. The type is "
68 : "listed as the first template parameter to `assert_conforms_to` "
69 : "and the protocol is listed as the second template parameter. "
70 : "Have you forgotten to (publicly) inherit the type from "
71 : "tt::ConformsTo<Protocol>?");
72 : // Implicitly instantiate Protocol::test in order to test conformance
73 : static_assert(
74 : not std::is_same_v<
75 : decltype(typename Protocol::template test<ConformingType>{}), void>);
76 : };
77 :
78 : template <typename ConformingType, typename Protocol>
79 0 : static constexpr bool assert_conforms_to_v =
80 : assert_conforms_to<ConformingType, Protocol>::value;
81 : /// @}
82 :
83 : } // namespace tt
|