c++ - reducing syntax "noise" without using a macro -
i'm trying find way of reducing bit of syntax "noise" without resorting macro. following code:
struct base { base() = delete; }; struct tag1 final : private base { static constexpr const char* name = "tag1"; }; template <typename t> std::string name() { return t::name; } // ... int main() { const std::string name1(name<tag1>()); return 0; }
it nice rid of of static constexpr const char*
(not mention other) syntax gets annoying repeat tag2
, tag3
, etc. plus, part of of interesting tag1
, rest "noise". straight-forward solution is use macro:
#define make_tag(tag_name) struct tag_name final : private base { \ static constexpr const char* name = #tag_name; } make_tag(tag2); // ... const std::string name2(name<tag2>());
the macro-based make_tag(tag2);
syntax has removed of "noise" leaving tag2
quite prominent. added benefit of macro tag_name
can turned string literal prevents copy-paste errors.
an "obvious" possible solution might pass name
template argument
template<const char* name> base { ... }; struct tag3 final : private base<"tag3"> {};
but that's not supported c++. clever work-around, answer below, use variadic template:
template<char... s> struct base { base() = delete; static std::string name() { return{ s... }; } }; struct tag4 final : base<'t', 'a', 'g', '4'> { }; template <typename t> std::string name() { return t::name(); }
this reduce of noise, requires writing 't', 'a', 'g', '4'
instead of "tag4"
. run-time solution succinct
struct base { const std::string name; base(const std::string& name) : name(name) {} }; struct tag5 final : base { tag5() : base("tag5") {} }; template <typename t> std::string name() { return t().name; }
but that's not entirely satisfying tag5
can instantiated, ideally doesn't make sense. also, it's necessary write tag5
3 times, isn't dry.
is there way further simplify (i.e., less typing) code above? ... without using macro?
if you're willing type out characters individually, can following:
template<char... s> struct base { base() = delete; static std::string name(){ return {s...}; } }; struct tag1 final : private base<'t','a','g','1'> {using base::name;}; struct tag2 final : private base<'t','a','g','2'> {using base::name;};
demo
call so:
std::cout << tag1::name() << std::endl; std::cout << tag2::name() << std::endl;
i had add using base::name
in derived classes because you're using private inheritance. if inheritance becomes protected
or public
, don't need that.
the gist of name()
function in base create character array can construct string from. use variadic parameter pack expansion create array.
Comments
Post a Comment