If you need to get name of derived class from base class, then you obviously need virtual
function, not static
. And to minimize code you need to type just use macro.
Simple way:
#include <iostream>
#include <string_view>
#define DECLARE_GETNAME(X) \
virtual std::string_view getName() { \
return #X; \
}
class Base {
public:
virtual ~Base() = default;
DECLARE_GETNAME(Base)
};
class Derived : public Base{
DECLARE_GETNAME(Derived)
};
int main()
{
Derived d;
Base& b = d;
std::cout << b.getName();
}
If you don't want to type class name every time, you can do it also, but little bit more complicated. Something like that:
#include <iostream>
#include <string_view>
template<typename T>
struct TypeName {
constexpr static std::string_view fullname_intern() {
#if defined(__clang__) || defined(__GNUC__)
return __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
return __FUNCSIG__;
#else
#error "Unsupported compiler"
#endif
}
constexpr static std::string_view name() {
size_t prefix_len = TypeName<void>::fullname_intern().find("void");
size_t multiple = TypeName<void>::fullname_intern().size() - TypeName<int>::fullname_intern().size();
size_t dummy_len = TypeName<void>::fullname_intern().size() - 4*multiple;
size_t target_len = (fullname_intern().size() - dummy_len)/multiple;
std::string_view rv = fullname_intern().substr(prefix_len, target_len);
if (rv.rfind(' ') == rv.npos)
return rv;
return rv.substr(rv.rfind(' ')+1);
}
using type = T;
constexpr static std::string_view value = name();
};
#define DECLARE_GETNAME() \
virtual std::string_view getName() { \
return TypeName<std::remove_cvref_t<decltype(*this)>>::value; \
}
class Base {
public:
virtual ~Base() = default;
DECLARE_GETNAME()
};
class Derived : public Base{
DECLARE_GETNAME()
};
int main()
{
Derived d;
Base& b = d;
std::cout << b.getName();
}
Code to get type name copied from here: https://stackoverflow.com/a/68139582/11680056