• Stars
    star
    572
  • Rank 77,995 (Top 2 %)
  • Language
    C++
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Compile Time Type Information for C++

CTTI badge Build Status Join the chat at https://gitter.im/Manu343726/ctti

Compile Time Type Information for the C++ programming language.

Background

We know C++ is a statically typed compiled language, but it's disappointing that we cannot even get the name of a C++ type at compile time, having to use RTTI (Run Time Type Information) which introduces a lot of overhead. In fact, that's one of the most feared features of C++, usually disabled in performance dependent scenarios such as videogames programming.

This library aims to provide features similar to RTTI std::type_info at compile-time, currently constexpr type name and a constexpr replacement of std::type_index for indexing maps with types.

#include "ctti/type_id.hpp"

int main()
{
    static_assert(ctti::type_id<int>() != ctti::type_id("hello"), "compile-time type-id comparison");

    std::unordered_map<ctti::type_id_t, std::size_t> sizeof_map;

    sizeof_map[ctti::type_id<int>()] = sizeof(int);
}

Support and current status

This was tested on Visual Studio 2015, GCC 5.2.0, MinGW GCC 5.1, Clang >3.6.2, and cygwin Clang 3.5.2. ctti does no use of generalized constexpr and must work on C++11 mode, but it needs support of constexpr __func__-like variables in the compiler. All major compilers except GCC before 5.1 support this.

Features

  • ctti::nameof<T>(): constexpr demangled full qualified type names.
  • ctti::nameof<T, T Value>(): constexpr demangled value strings.
  • ctti::static_calue<T, Value>: std::integral_constant on steroids, to pass values as template parameters.
  • CTTI_STATIC_VALUE(Value): Handy macro to instance a ctti::static_value from the given value.
  • ctti::detailed_nameof<>(): Alternatives to nameof with detailed name info, supporting non-qualified names, getting qualifiers, etc. See ctti::name_t for details.
  • ctti::nameof_v<> and ctti::detailed_nameof_v<>: C++14 variable template alternatives to the nameof family of functions. Thanks C++ Bruja for this suggestion.
  • ctti::type_id<T>(): constexpr std::type_info-like type identifier. See ctti::type_id_t bellow for details.
  • ctti::id_from_name(name): Get the type id corresponding to the given typename.
  • ctti::unnamed_type_id<T>(): constexpr std::type_info-like hash-only type identifier. See ctti::unnamed_type_id_t bellow for details.
  • Symbol based introspection: Automatic serialization (wip), object conversion, etc. See symbolic introspection bellow.

Name customization

The names ctti return for a given static value or typename can be overrided with the ctti_nameof() function. This can be achieved in two ways:

  • Intrusive override: The user defined class defines a ctti_nameof() function as part of its static public API:
    struct Foo
    {
        static constexpr const char* ctti_nameof()
        {
            return "foo";
        }
    };
  • Non-intrusive override: A ctti_nameof(type/value tag) customization point is defined in the type/value namespace:
    #include <string>
    
    namespace std
    {
        constexpr const char* ctti_nameof(ctti::type_tag<std::string>)
        {
             return "std::string"; // instead of "std::__foobar::basic_string<char>"
        }
    }

ctti::detail::cstring

cstring is a constexpr implementation of an string view and the core of ctti. All strings returned by the ctti API are represented by this type. It supports slicing via operator()(begin index, end index), subscript, hashing, string padding, comparison operators, print to std::ostream, etc.

constexpr ctti::detail::cstring str{"hello world"};
constexpr ctti::detail::cstring str2{"   hello world   "};

static_assert(str(0, 5) == "hello");
static_assert(str2.pad(2, 2) == str);

constexpr std::uint64_t hash = str.hash(); // fnv1a hash or "hello world"

ctti::name_t

name_t contains methods to extract information of a name. Given a full qualified name (like those returned by ctti::nameof()) a name_t can be constructed and queried:

struct Foo
{
    int i;
};

constexpr ctti::name_t FooName = ctti::detailed_nameof<CTTI_STATIC_VALUE(&Foo::i)>();

int main()
{
    std::cout << FooName.name();                  // prints "i"
    std::cout << FooName.full_name();             // prints "&Foo::i"
    std::cout << FooName.full_homogeneous_name(); // prints "Foo::i"
    std::cout << FooName.qualifier(0);            // prints "Foo"
}

All methods in name_t are constexpr and return cstrings.

ctti::type_id_t

A constexpr class representing an object identifier. It has the minimal constexpr comparable interface to be used as a key type. The id is based on a fnv1a hash of the type name, which can be obtained by calling type_id_t::hash(). std::hash is specialized for this type.

std::unordered_map<ctti::type_id_t, void*(*)()> factories;

factories[ctti::type_id<int>()] =         []() -> void* { return new int{}; };
factories[ctti::type_id<std::string>()] = []() -> void* { return new std::string{}; };

void* int_var = factories[ctti::id_from_name("int")]();

ctti::unnamed_type_id_t

A lightweight version of type_id_t which only stores the type hash (ctti::type_id_t stores the name string, which takes one pointer and a size_t, and computes hash on demand. unnamed_type_id_t stores the std::uint64_t hash only).

struct object
{
    ctti::unnamed_type_id_t type_id;
    void* data;
};

Symbolic introspection

ctti implements object introspection by working with abstract "symbols" defined by the user:

#include <ctti/symbol.hpp>

CTTI_DEFINE_SYMBOL(foo);

the CTTI_DEFINE_SYMBOL macro defines an abstract identifier, a symbol, in the current namespace. After its definition, classes can be asked for members through that symbo:

CTTI_DEFINE_SYMBOL(i);

struct my_struct
{
    int i;
};

static_assert(i::is_member_of<my_struct>(), "Has my_struct a member named 'i'?");

with symbols as non-intrusive generic member identifiers, objects can be manipulated in a generic way:

#include <ctti/symbol.hpp>
#include <ctti/tie.hpp>

CTTI_DEFINE_SYMBOL(a);
CTTI_DEFINE_SYMBOL(b);
CTTI_DEFINE_SYMBOL(c);

struct foo
{
    int a, b, c;
};


int var_a, var_b;
foo my_foo{1, 2, 3};

ctti::tie<a, b>(var_a, var_b) = my_foo;

assert(var_a == 1);
assert(var_a == 2);
struct bar
{
    int a, b;
};

bar my_bar;

// Copy my_foo.a to my_bar.a and my_foo.b to my_bar.b:
ctti::map(my_foo, my_bar, ctti::mapping<a, a>(), ctti::mapping<b, b>());

Conditional features

ctti has a set of conditional features that depend on non-C++11 language features. This ctti features can be controlled by different macros:

  • ctti::nameof_v/detailed_nameof_v are declared only if CTTI_HAS_VARIABLE_TEMPLATES is defined. Enabled by default if the compiler supports variable templates.
  • ctti::nameof/detailed_nameof could work with enum values if the compiler prints those values as part of their PRETTY_FUNCTION variables. ctti controls this by defining the CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION. If this macro is not defined ctti gives no guarantee you will get the right string from an enum value.

Acknowledgments

Thanks a lot to Jonathan "foonathan" Müller, both for the constexpr hash and the idea for the __PRETTY_FUNCTION__ trick.

License

This project is licensed under the MIT license. See LICENSE.md for more details.

More Repositories

1

tinyrefl

A work in progress minimal C++ static reflection API and codegen tool.
C++
255
star
2

siplasplas

A library for C++ reflection and introspection
C++
195
star
3

Turbo

C++11 metaprogramming library
C++
110
star
4

snail

Continuation-ready container algorithms from STL algorithms
C++
60
star
5

unittest

C++ unit testing and mocking made easy
C++
55
star
6

Polyop

Overridable universal operator overloading for C++14
C++
20
star
7

gcc-concepts-bugs

A repository to host C++ Concepts Lite TS examples, to help with GCC bug reporting
C++
15
star
8

spacevim

My vim SpaceVim-based config
Vim Script
15
star
9

coroutine

A simple stackful coroutine implementation in C++11
C++
10
star
10

libexecstream

CMake-ready libexecstream library
C++
8
star
11

strings

Examples of string implementation techniques in C++11/14
C++
8
star
12

dotfiles

My personal dotfiles repository
Shell
8
star
13

cppascii

Code snippets, ejemplos, utilidades, etc
C++
7
star
14

clang-conan-packages

conan.io recipes for llvm and clang libraries
Python
7
star
15

meetingcpp2016

Slides and other stuff from my meetingcpp 2016 talk
CMake
5
star
16

cpp-dod-tests

Performance tests for an encapsulation-enabled Data Oriented Design implementation
Assembly
5
star
17

cppcon2019

Materials of CppCon 2019 talk "Next Generation Unit Testing Using Static Reflection"
5
star
18

meetingcpp2018

Slides from "C++, QML, and static reflection" talk at Meeting C++ 2018
4
star
19

tiny-metaprogramming-library

A practical example of high-level metaprogramming as a growing up library
C++
4
star
20

raytracer

My implementation of "Raytracing In One Weekend" by Peter Shirley
C++
3
star
21

Cpp11CustomLogClass

C++11 custom Log class. Code example of a response to stackoverflow question: http://stackoverflow.com/questions/17595957/operator-overloading-in-c-for-logging-purposes/
Shell
3
star
22

traces

Type safe Tracy API
C++
3
star
23

telegram-reactive

Example C++ telegram bot using a reactive API
C++
3
star
24

rainbow

C++
2
star
25

uftrace-docker

Docker image for uftracer C/C++ profiler
Dockerfile
2
star
26

C--

The sandbox where we show our increasingly depressing C++ skills
C++
2
star
27

ProyectoOmegauhm

Web de consulta y recursos centralizados para los alumnos de FDI
CSS
2
star
28

TemplateMetaprogramming101

Scripts, utilities, and examples for my Modern C++ Template Metaprogramming workshops
C++
1
star
29

worm

C++
1
star
30

TTL

C++11 Tuple Template Library
C++
1
star
31

xml

The neXt Metaprogramming Library
1
star
32

WALLE

Prácticas de Tecnología de la Programación
Java
1
star
33

PracticasIA

Java
1
star
34

efsw

conan.io package for the Entropia Filesystem Watcher library
Python
1
star
35

cmake

CMake
1
star
36

biicode-posts

C
1
star
37

cucaracha

An emulator for a CPU of my own
Go
1
star
38

TerminalWorkspace

My personal zsh, tmux, and vim configurations. No guarantees, works for me at least.
Shell
1
star