[mrpt-typemeta]
Overview
Metaprogramming header-only library to obtain constexpr
textual string representations of enum types and type names, including smart pointers and complex STL compound types.
Library mrpt-typemeta
This library is part of MRPT but has no dependencies, so it can be installed in Debian-based systems with:
sudo apt install libmrpt-typemeta-dev
Read also how to import MRPT into your CMake scripts.
Example #1: compile-time type/struct/class names to strings
Use mrpt::typemeta::TTypeName to extract a constexpr
string with a compiler-independent representation of arbitrarily-complex types and STL containers. Note that creating objects from a run-time string representation of its type is handled in a different library ([mrpt-serialization]).
See: typemeta_TTypeName/test.cpp
#include <mrpt/typemeta/TTypeName.h> #include <mrpt/typemeta/TTypeName_stl.h> #include <iostream> #include <memory> // shared_ptr // Declare custom user types: struct MyFooClass { using Ptr = std::shared_ptr<MyFooClass>; }; namespace MyNS { struct MyBarClass { }; struct MyBarClass2 { DECLARE_TTYPENAME_CLASSNAME(MyNS::MyBarClass2) }; } // namespace MyNS DECLARE_CUSTOM_TTYPENAME(MyFooClass); DECLARE_CUSTOM_TTYPENAME(MyNS::MyBarClass); void Test_TypeName() { using namespace std; using namespace mrpt::typemeta; // Evaluation of type names as constexpr strings: constexpr auto s1 = TTypeName<int32_t>::get(); cout << s1 << endl; cout << TTypeName<set<vector<double>>>::get() << endl; // Evaluation of user-defined types: cout << TTypeName<MyFooClass>::get() << endl; cout << TTypeName<MyFooClass::Ptr>::get() << endl; cout << TTypeName<MyNS::MyBarClass>::get() << endl; cout << TTypeName<MyNS::MyBarClass2>::get() << endl; // STL typenames as strings: cout << TTypeName<double>::get() << endl; cout << TTypeName<vector<double>>::get() << endl; cout << TTypeName<array<int32_t, 5>>::get() << endl; cout << TTypeName<set<double>>::get() << endl; cout << TTypeName<pair<int32_t, pair<int32_t, int32_t>>>::get() << endl; cout << TTypeName<map<double, set<int32_t>>>::get() << endl; cout << TTypeName<set< multimap<double, pair<MyFooClass, MyNS::MyBarClass2>>>>::get() << endl; }
Output:
int32_t std::set<std::vector<double>> MyFooClass std::shared_ptr<MyFooClass> MyNS::MyBarClass MyNS::MyBarClass2 double std::vector<double> std::array<int32_t,5> std::set<double> std::pair<int32_t,std::pair<int32_t,int32_t>> std::map<double,std::set<int32_t>> std::set<std::multimap<double,std::pair<MyFooClass,MyNS::MyBarClass2>>>
Example #2: compile-time constexpr strings manipulation
See: typemeta_StaticString/test.cpp
#include <mrpt/typemeta/static_string.h> #include <iostream> void Test_StaticString() { using namespace std; using namespace mrpt::typemeta; constexpr string_literal<3> s = "foo"; cout << "string_literal<3>=" << s << endl; constexpr auto a = literal("foo"); constexpr auto b = literal("bar"); // In GCC7 this can be "constexpr", but it fails in MSVC 2017 (!) auto ab = a + b; cout << "a=" << a << endl; cout << "b=" << b << endl; cout << "a+b=" << ab << endl; static_assert(ab.size() == 6, "***"); cout << "(a+b).size()=" << ab.size() << endl; cout << "(a+b)[0]=" << ab[0] << endl; cout << "(a+b)[5]=" << ab[5] << endl; }
Output:
string_literal<3>=foo a=foo b=bar a+b=foobar (a+b).size()=6 (a+b)[0]=f (a+b)[5]=r
Example #3: compile-time numbers to strings
See: typemeta_StaticString/test.cpp
#include <mrpt/typemeta/num_to_string.h> #include <iostream> void Test_StaticNum2Str() { using namespace std; using namespace mrpt::typemeta; constexpr auto n42 = num_to_string<42>::value; constexpr auto n9999 = num_to_string<9999>::value; cout << "42 as string=" << n42 << endl; cout << "9999 as string=" << n9999 << endl; }
Output:
42 as string=42 9999 as string=9999
Example #4: enum values to/from strings
See: typemeta_TEnumType/test.cpp
#include <mrpt/typemeta/TEnumType.h> #include <iostream> #include <string> // Example declaration of "enum class" enum class TestColors { Black = 0, Gray = 7, White = 15 }; MRPT_ENUM_TYPE_BEGIN(TestColors) MRPT_FILL_ENUM_MEMBER(TestColors, Black); MRPT_FILL_ENUM_MEMBER(TestColors, Gray); MRPT_FILL_ENUM_MEMBER(TestColors, White); MRPT_ENUM_TYPE_END() // Example declaration of plain enum enum Directions { North, East, South, West }; // Example declaration of "enum class" MRPT_ENUM_TYPE_BEGIN(Directions) MRPT_FILL_ENUM(North); MRPT_FILL_ENUM(East); MRPT_FILL_ENUM(South); MRPT_FILL_ENUM(West); MRPT_ENUM_TYPE_END() void Test_EnumType() { using namespace std; using namespace mrpt::typemeta; cout << "White => " << (int)TEnumType<TestColors>::name2value("White") << endl; cout << "Black => " << (int)TEnumType<TestColors>::name2value("Black") << endl; cout << "Gray => " << (int)TEnumType<TestColors>::name2value("Gray") << endl; cout << "7 <= " << TEnumType<TestColors>::value2name(TestColors(7)) << endl; }
Output:
White => 15 Black => 0 Gray => 7 7 <= Gray
Library contents
// structs template <typename ENUMTYPE> struct mrpt::typemeta::TEnumType; template <typename ENUMTYPE> struct mrpt::typemeta::TEnumTypeFiller; template <typename T> struct mrpt::typemeta::TTypeName;