tagval
0.2.0
Modern C++23 header-only library of tagged values (open/closed enumerations with metadata)
Loading...
Searching...
No Matches
macros.hpp
Go to the documentation of this file.
1
#pragma once
2
14
15
#include <
tagval/entry.hpp
>
16
#include <
tagval/kind_registry.hpp
>
17
#include <
tagval/openended_registry.hpp
>
18
19
// `[[gnu::used]]` keeps the inline registrar variable in the final binary even
20
// when nothing else in its translation unit is referenced — required for extern
21
// entries built into a static archive. GCC and Clang (including Apple Clang)
22
// honour the attribute; MSVC needs `/INCLUDE:<mangled>` on the linker line and
23
// is not handled here (CI does not exercise MSVC for v0.1.0).
24
#if defined(__GNUC__) || defined(__clang__)
25
#define TAGVAL_DETAIL_USED [[gnu::used]]
26
#else
27
#define TAGVAL_DETAIL_USED
28
#endif
29
30
// In-class entry whose code is derived from the function name.
31
//
32
// TAGVAL_ENTRY(Status, Active, active);
33
// TAGVAL_ENTRY(Status, Inactive, inactive, "Inactive", "mdi:off");
34
#define TAGVAL_ENTRY(Owner, TypeName, FuncName, ...) \
35
struct TypeName : ::tagval::Entry<Owner, #FuncName __VA_OPT__(, ) __VA_ARGS__> {}; \
36
[[maybe_unused]] [[nodiscard]] static auto const& FuncName() { \
37
return base_t::template value<TypeName>(); \
38
}
39
40
// In-class entry with explicit code:
41
//
42
// TAGVAL_ENTRY_AS(Status, Archived, is_archived, "archived", "Archived");
43
#define TAGVAL_ENTRY_AS(Owner, TypeName, FuncName, Code, ...) \
44
struct TypeName : ::tagval::Entry<Owner, Code __VA_OPT__(, ) __VA_ARGS__> {}; \
45
[[maybe_unused]] [[nodiscard]] static auto const& FuncName() { \
46
return base_t::template value<TypeName>(); \
47
}
48
49
// External entry: declared at namespace scope, always registers.
50
#define TAGVAL_EXTERN_ENTRY(Owner, TypeName, FuncName, ...) \
51
struct TypeName : ::tagval::Entry<Owner, #FuncName __VA_OPT__(, ) __VA_ARGS__> {}; \
52
[[maybe_unused]] [[nodiscard]] inline auto const& FuncName() { \
53
return Owner::template value<TypeName>(); \
54
} \
55
/* NOLINTNEXTLINE(readability-identifier-naming) */
\
56
TAGVAL_DETAIL_USED [[maybe_unused]] inline const bool TypeName##_registered_ = [] { \
57
::tagval::OpenEndedRegistry<Owner>::add(&::tagval::metadata_v<TypeName>); \
58
return true; \
59
}()
60
61
#define TAGVAL_EXTERN_ENTRY_AS(Owner, TypeName, FuncName, Code, ...) \
62
struct TypeName : ::tagval::Entry<Owner, Code __VA_OPT__(, ) __VA_ARGS__> {}; \
63
[[maybe_unused]] [[nodiscard]] inline auto const& FuncName() { \
64
return Owner::template value<TypeName>(); \
65
} \
66
/* NOLINTNEXTLINE(readability-identifier-naming) */
\
67
TAGVAL_DETAIL_USED [[maybe_unused]] inline const bool TypeName##_registered_ = [] { \
68
::tagval::OpenEndedRegistry<Owner>::add(&::tagval::metadata_v<TypeName>); \
69
return true; \
70
}()
71
72
// Internal helpers for token pasting that survives one round of macro
73
// expansion — needed so __LINE__ in TAGVAL_REGISTER_KIND actually expands
74
// before the ##. Don't use directly.
75
#define TAGVAL_DETAIL_PASTE2(a, b) a##b
76
#define TAGVAL_DETAIL_PASTE(a, b) TAGVAL_DETAIL_PASTE2(a, b)
77
78
// Register a kind in the program-wide tagval::KindRegistry. Place at
79
// namespace scope (typically immediately after the kind's class definition,
80
// in either a header or a .cpp). Opt-in: kinds that are never registered do
81
// not appear in KindRegistry::all(). Idempotent on the kind's id; the same
82
// macro placed in multiple TUs is safe.
83
//
84
// TAGVAL_REGISTER_KIND(Status);
85
// TAGVAL_REGISTER_KIND(::vendor::PaymentMethod);
86
//
87
// The kind argument may be fully qualified — the registrar variable name is
88
// generated from __LINE__ so namespace-qualified types work directly without
89
// an extra alias. (`__COUNTER__` would also work but is flagged as a C2y
90
// extension under -Wc2y-extensions.) Limitation: two TAGVAL_REGISTER_KIND
91
// invocations on the same line of the same TU will collide — keep them on
92
// separate lines.
93
//
94
// Inherits the static-archive caveat from TAGVAL_EXTERN_ENTRY: if the macro
95
// lands in a TU that's only inside a .a and nothing else in that TU is
96
// referenced from the consumer, the registrar may be dead-stripped. Same
97
// workarounds apply (CMake OBJECT library, --whole-archive, -force_load).
98
#define TAGVAL_REGISTER_KIND(KindType) \
99
/* NOLINTNEXTLINE(readability-identifier-naming) */
\
100
TAGVAL_DETAIL_USED [[maybe_unused]] inline const bool TAGVAL_DETAIL_PASTE( \
101
tagval_kind_registered_, __LINE__) = [] { \
102
::tagval::KindRegistry::register_kind<KindType>(); \
103
return true; \
104
}()
entry.hpp
Compile-time Entry NTTP and the runtime-view TagValMetadata struct.
kind_registry.hpp
Program-wide registry of every tag-value kind that opts in via the TAGVAL_REGISTER_KIND macro.
openended_registry.hpp
Per-Owner runtime registry used by OpenEnded kinds.
include
tagval
macros.hpp
Generated by
1.9.8