diff --git a/include/mserialize/make_template_tag.hpp b/include/mserialize/make_template_tag.hpp index 6e7e621..d58be3c 100644 --- a/include/mserialize/make_template_tag.hpp +++ b/include/mserialize/make_template_tag.hpp @@ -78,12 +78,25 @@ // MSERIALIZE_UNTUPLE((Tuple)) = Tuple // MSERIALIZE_STRINGIZE_LIST(Tuple) ~= "Tuple" // +// tag_guard: to make has_tag report correctly if T has a tag or not, +// (that depends on the template parameter), we first check if every member +// has a tag (see conjunction), then either create a constructible member +// (true_type, if every member has a tag), or a not-constructible member, +// (BuiltinTag), making this spec also non-constructible - has_tag +// checks constructibility. #define MSERIALIZE_MAKE_TEMPLATE_TAG(TemplateArgs, ...) \ namespace mserialize { \ template \ struct CustomTag \ { \ using T = MSERIALIZE_UNTUPLE(MSERIALIZE_FIRST(__VA_ARGS__)); \ + std::conditional_t< \ + mserialize::detail::conjunction< \ + MSERIALIZE_FOREACH(MSERIALIZE_HAS_TAG, _, __VA_ARGS__) \ + std::true_type>::value, \ + std::true_type, \ + mserialize::detail::BuiltinTag \ + > tag_guard; \ static constexpr auto tag_string() \ { \ return cx_strcat( \ @@ -108,4 +121,8 @@ #define MSERIALIZE_STRINGIZE_LIST_I(_, a) "," #a +#define MSERIALIZE_HAS_TAG(_, m) \ + mserialize::detail::has_tag, \ + /**/ + #endif // MSERIALIZE_MAKE_TEMPLATE_TAG_HPP diff --git a/test/unit/mserialize/tag.cpp b/test/unit/mserialize/tag.cpp index 593fd18..4478995 100644 --- a/test/unit/mserialize/tag.cpp +++ b/test/unit/mserialize/tag.cpp @@ -188,3 +188,23 @@ MSERIALIZE_MAKE_DERIVED_STRUCT_TAG(Derived2, (Derived1)) static_assert(mserialize::tag() == "{Derived2`'{Derived1`'{Base2`'{Base1`a'i}`b'i}`'{Base3`c'[c}`d'i`e'i}}", ""); #endif // _WIN32 + +// test has_tag + +// This is a private method, but still useful sometimes, +// e.g: user wants to check if a template with a random member is loggable or not. + +struct Adapted{}; +MSERIALIZE_MAKE_STRUCT_TAG(Adapted) + +struct NotAdapted{}; + +template +struct Nest +{ + Nested n; +}; +MSERIALIZE_MAKE_TEMPLATE_TAG((typename Nested), (Nest), n) + +static_assert(mserialize::detail::has_tag>::value, ""); +static_assert(!mserialize::detail::has_tag>::value, "");