Is there any way I can evaluate decltype
in a C++ macro? My main motivation is to create a macro that is able to determine the type of this
and convert it to a string.
If it's not possible to use decltype
is there any other way a macro used inside a class declaration can get the type of the class as a string?
Is there any way I can evaluate
decltype
in a C++ macro?
No, since macros are strictly evaluated before decltype
.
As far as I know there is no way to get the name of the class as a macro, full stop. Any such way would have to be supported by a compiler-generated macro.
However, you can use typeid
to get the mangled name (strictly speaking, an implementation-defined representation), and then use compiler-specific tools to retrieve the demangled name from that.
For instance, GCC offers the demangling library to do this.
Here’s a minimal example online demo
:
#define THIS_CLASS_NAME() demangled(typeid(*this).name())
std::string demangled(char const* tname) {
std::unique_ptr<char, void(*)(void*)>
name{abi::__cxa_demangle(tname, 0, 0, nullptr), std::free};
return {name.get()};
}
Usage:
namespace foo {
template <typename T>
struct bar {
bar() { std::cout << THIS_CLASS_NAME() << '\n'; }
};
}
int main() {
foo::bar<int> b;
}
Yields:
foo::bar<int>
Macros are expanded before any code is compiled, so unfortunately they don't have any concept of types.
Depending on your needs, you might be able to use a traits class instead though. It's theoretically a bit more efficient and portable than RTTI and typeid, but it only works for types you've explicitly told it about. For example:
template <typename T>
struct Traits
{
static const char * TYPE_NAME;
};
// Generic definition as a fall-back:
template <typename T> const char * Traits<T>::TYPE_NAME = "unknown";
// Explicit definitions
template < > const char * Traits< int >::TYPE_NAME = "int";
template < > const char * Traits< float >::TYPE_NAME = "float";
template < > const char * Traits< ExampleClass >::TYPE_NAME = "ExampleClass";
The explicit definitions are a bit cumbersome, so you could create a macro to make them more readable:
#define DECLARE_TYPE_TRAIT(name) template < > const char * Traits<name>::TYPE_NAME = #name;
DECLARE_TYPE_TRAITS(int)
DECLARE_TYPE_TRAITS(float)
DECLARE_TYPE_TRAITS(ExampleClass)
Using the traits class in your code is really easy. You just instantiate the traits template on whatever type you want to look up, and access the TYPE_NAME member:
int foo;
ExampleClass blah;
cout << Traits<decltype(foo)>::TYPE_NAME << endl;
cout << Traits<decltype(blah)>::TYPE_NAME << endl;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With