I'm trying to find a way of reducing a bit of syntax "noise" without resorting to a macro. For the 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 would be nice to get rid of the some of the static constexpr const char*
(not to mention the other) syntax as it gets annoying to repeat that for tag2
, tag3
, etc. Plus, the only part of all of that which is really interesting is tag1
, the rest is "noise". The straight-forward solution is to use a 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 all of the "noise" leaving tag2
quite prominent. An added benefit of the macro is that the tag_name
can easily be turned into a string literal which prevents copy-paste errors.
An "obvious" possible solution might be to pass name
as a template argument
template<const char* name> base { ... };
struct tag3 final : private base<"tag3"> {};
but that's not supported by C++. A clever work-around, from the answer below, is to 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 does reduce much of the noise, but requires writing 't', 'a', 'g', '4'
instead of "tag4"
. A run-time solution is fairly 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 as tag5
can now be instantiated, which ideally doesn't make sense. Also, it's now necessary to write tag5
three times, which isn't very DRY.
Is there a way to further simplify (i.e., less typing) the code above? ... without using a macro?