简体   繁体   中英

Compiler independent class name

I need to print the name of a class such as

template<typename... Args>
struct S{};

Using typeid(S<int,std::vector<double>>).name() its fairly simple to print something representative. With boost demangle it might even be readable on gcc.

Is there any way to get the name so the name is the same between different compilers?

Not really. The mangled name is, in general, compiler-specific. See the table titled "How different compilers mangle the same functions" on Wikipedia

Demo.

#include <string_view>
#include <vector>

template<typename... Args>
struct S{};

template <typename T>
constexpr auto type_name()
{
    std::string_view name, prefix, suffix;
#ifdef __clang__
    name = __PRETTY_FUNCTION__;
    prefix = "auto type_name() [T = ";
    suffix = "]";
#elif defined(__GNUC__)
    name = __PRETTY_FUNCTION__;
    prefix = "constexpr auto type_name() [with T = ";
    suffix = "]";
#elif defined(_MSC_VER)
    name = __FUNCSIG__;
    prefix = "auto __cdecl type_name<";
    suffix = ">(void)";
#endif
    name.remove_prefix(prefix.size());
    name.remove_suffix(suffix.size());
    return name;
}   

int main()
{
#ifdef _MSC_VER
   static_assert(type_name<S<int, std::vector<double>>>() == "struct S<int,class std::vector<double,class std::allocator<double> > >");
#else
   static_assert(type_name<S<int, std::vector<double>>>() == "S<int, std::vector<double, std::allocator<double> > >");
#endif
}

Is it possible to print a variable's type in standard C++?

No. There is no portable way to get the name as a string for an arbitrary type across all platforms.

You can potentially write a function template that uses platform-specific code to determine a name of a template parameter, but that is tricky to do, and brittle.

Alternatively, if you only want names for your types, or you are willing to register names for every type that you need a name for, then you can do something like:

some_library::register_type_name<some_type>("some_type");
some_library::register_type_name<some_other_type>("some_other_type");

adding entries to an internal map of typeid to string. This could be hidden behind a macro like REGISTER_TYPE(x) , but it would still need to be done for every type.

You can then easily write some_library::lookup_type_name<some_type>() which searches the registered types and returns the string. You could also write an overload especially for S which looked up the name of its template parameters too.

You could write a library that provides a name for all standard types, plus containers of standard types, plus make it extensible for project specific types...

That's exactly what the "type name" sub-library in Celma does.

See examples of the usage in the test file: https://github.com/Gemini67/Celma/blob/master/src/library/common/test/test_type_name.cpp

The starting point for the whole library is here: https://github.com/Gemini67/Celma

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM