Good question, thought I'd throw my hat into the ring... I guess you can pass pointers to static variables as non-type template arguments. From C++20 it looks like it won't be an issue... Until then, here is some cheap macro to make it work.
template <const char *Name, typename T>
struct TaggedValue {
static constexpr char const *name{Name};
T value;
friend ostream &operator<<(ostream &o, const TaggedValue &a) {
return o << a.name << " = " << a.value;
}
};
#define ST(name, type)\
const char ST_name_##name[]{#name};\
using name = TaggedValue<ST_name_##name,type>;
ST(Foo, int);
ST(Bar, int);
ST(Bax, string);
int main() {
cout << Foo{3} << endl;
cout << Bar{5} << endl;
cout << Bax{"somthing"} << endl;
}
C++20 comment (EDIT)
I've not used c++ much lately, so I'm sorry if this isn't 100% correct. There's a comment about why this wouldn't be an issue in c++20. According to the reference on template_parameters:
A non-type template parameter must have a structural type, which is one of the following types (optionally cv-qualified, the qualifiers are ignored):
...
- a floating-point type;
- a literal class type with the following properties:
- all base classes and non-static data members are public and non-mutable and
- the types of all base classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
This had led me to believe that the following code would work:
struct conststr
{
const char * const p;
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a)/*, sz(N - 1) */{}
};
template<conststr s>
struct A{};
int main(int argc, char **argv) {
A<conststr("foo")> x;
}
(Again, I'm not 100% sure if that's 100% correct). But it doesn't, at least not on my machine with g++ -std=c++2a
(g++ --version == g++ (Debian 8.3.0-6) 8.3.0
). It doesn't work with double
either. This guy gives a much more detailed account of the history here, and there are probably better references, and I could just be completely incorrect.