# Compound types

A type is a compound_t type (in pygccxml) if it is one of the following: volatile_t, restrict_t, const_t, pointer_t, reference_t, elaborated_t, array_t or member_variable_type_t.

The exact c++ definition of compound types embraces more types, but for different reasons (mostly legacy), the definition in pygccxml is slightly different.

Let’s consider the following c++ file:

    int const c1 = 0;
    const int c2 = 0;

    volatile const int cv1 = 0;
    const volatile int cv2 = 0;

    const int * const cptr1 = 0;

The following code will show what to expect from compound types, how they are chained, and how their order is defined in pygccxml.

    from pygccxml import utils
    from pygccxml import declarations
    from pygccxml import parser

    # Find out the c++ parser
    generator_path, generator_name = utils.find_xml_generator()

    # Configure the xml generator
    xml_generator_config = parser.xml_generator_configuration_t(
        xml_generator_path=generator_path,
        xml_generator=generator_name)

    # The c++ file we want to parse
    filename = "example.hpp"

    decls = parser.parse([filename], xml_generator_config)
    global_namespace = declarations.get_global_namespace(decls)

    c1 = global_namespace.variable("c1")
    print(str(c1), type(c1))
    # > 'c1 [variable]', <class 'pygccxml.declarations.variable.variable_t'>

    print(str(c1.decl_type), type(c1.decl_type))
    # > 'int const', <class 'pygccxml.declarations.cpptypes.const_t'>

    base = declarations.remove_const(c1.decl_type)
    print(str(base), type(base))
    # > 'int', <class 'pygccxml.declarations.cpptypes.int_t'>

    c2 = global_namespace.variable("c2")
    print(str(c2.decl_type), type(c2.decl_type))
    # > 'int const', <class 'pygccxml.declarations.cpptypes.const_t'>
    # Even if the declaration was defined as 'const int', pygccxml will always
    # output the const qualifier (and some other qualifiers) on the right hand
    # side (by convention).

    cv1 = global_namespace.variable("cv1")
    print(str(cv1.decl_type), type(cv1.decl_type))
    # > 'int const volatile', <class 'pygccxml.declarations.cpptypes.volatile_t'>

    # Remove one level:
    base = declarations.remove_volatile(cv1.decl_type)
    print(str(base), type(base))
    # > 'int const', <class 'pygccxml.declarations.cpptypes.const_t'>

    # Remove the second level:
    base = declarations.remove_const(base)
    print(str(base), type(base))
    # > 'int', <class 'pygccxml.declarations.cpptypes.int_t'>

    # We can also directly do this in one step:
    base = declarations.remove_cv(cv1.decl_type)
    print(str(base), type(base))
    # > 'int', <class 'pygccxml.declarations.cpptypes.int_t'>

    # As for consts, the const and volatile are on the right hand side
    # (by convention), and always in the same order
    cv2 = global_namespace.variable("cv2")
    print(str(cv2.decl_type), type(cv2.decl_type))
    # > 'int const volatile', <class 'pygccxml.declarations.cpptypes.volatile_t'>

    # And a last example with a pointer_t:
    cptr1 = global_namespace.variable("cptr1")
    print(str(cptr1.decl_type), type(cptr1.decl_type))
    # > 'int const * const', <class 'pygccxml.declarations.cpptypes.const_t'>)

    base = declarations.remove_const(cptr1.decl_type)
    print(str(base), type(base))
    # > 'int const *', <class 'pygccxml.declarations.cpptypes.pointer_t'>

    base = declarations.remove_pointer(base)
    print(str(base), type(base))
    # > 'int const', <class 'pygccxml.declarations.cpptypes.const_t'>)

    base = declarations.remove_const(base)
    print(str(base), type(base))
    # > 'int', <class 'pygccxml.declarations.cpptypes.int_t'>)