[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;