Overview
A named type is a class that provides a new type by wrapping an existing type. This allows a generic type (such as int) to be restricted to a narrower type (such as mipmap_level_t). The named type ensures, at compile time, that values assigned to it are of the restricted type, while maintaining most operations and efficiencies that apply to the wrapped type.
The essential features provided by named types are:
- Conversions to named types are type-safe.
- Conversions from named types to compatible types are either implicit or easily coerced.
Examples:
int kilometers = 5;
kilometers_t distance = 5;
kilometers_t distance2 = 5_kilometers
auto distance3 = 5_kilometers;
kilometers_t distance4 { 5 };
kilometers_t distance5;
kilometers_t distance6 = distance2;
kilometers_t distance7 { distance2 };
int distance8 { distance7 };
CppGraph© uses named types extensively. Pre-defned named types can be found in named types.
Advantages
- Type safety
- A compile error results on implicit construction or assignment from a different type, including from a corresponding value type.
- Readability
- The type no longer needs to be encoded in the variable name.
int bar_count;
bar_t count;
- Automatic initialization.
int bar_count;
bar_t count;
- Automatic reflection.
- Literals corresponding to named types are also strongly-typed.
Similarities
A named type is similar to its value type in the following ways:
- Its size is the same.
- Its memory representation is the same.
- It can be used implicitly anywhere a const reference to its value type can be used.
- Access to its value is as efficient as access to its value type, in most or all cases.
- Depending on compiler optimizations.
Declaration
To declare a named type, call CPPGRAPH_DECLARE_NAMED_TYPE() (or CPPGRAPH_DECLARE_DERIVED_NAMED_TYPE()), from the desired namespace.
namespace foo
{
}
foo::bar_t b;
Derived Named Types
A named type can be derived from another named type. At most 1 level of derivation is allowed. The derived named type can be used in place of its base named type.
namespace foo
{
}
void bar( distance_t const & distance );
foo::kilometers_t crow_flies{ 12_kilometers };
bar( crow_flies );
Named Type Names
To add a type name for a named type or derived named type, call CPPGRAPH_DECLARE_NAMED_TYPE_TYPENAME() from the cppgraph namespace.
Named Type Literals
A named type or derived named type can have a corresponding literal suffix declared using the macro CPPGRAPH_DECLARE_LITERAL() from the cppgraph::literals namespace:
namespace foo
{
}
{
}
auto foobar = 99_bar;
Pre-defined literal suffixes are literals.
Named Types as Properties
Named types can be used as properties. They are declared and accessed using the same macros and functions as built-in properties. Access is as efficient as that for built-in properties. Automatic serialization is performed for named type properties just as it is for built-in and user properties.
General Usage
Construction
Construction is type-safe. This is the purpose of named types. Named types are constructible in the following ways:
- The default constructor ensures that a named type is always initialized.
- The non-default constructor takes a variadic list of arguments. These are forwarded to the constructor of the value type.
- The static member function from_value() returns a named type instance constructed from a specified value whose type can be
static_cast to the value type.
- The compiler-generated copy constructor (and assignment operator) are used.
Value Access
The named_type_t class has been designed to provide easy and (where possible) transparent access to its value type in expressions. Some use cases and solutions are:
- Implicit access to the value type.
- The implicit cast operator provides this functionality in many situations.
- Explicit access to the value type, in the cases where implicit access fails.
- Access to members of a class in the case where the value type is a class.
- Transparent numeric operations are provided by the following:
- Comparison operators.
Conversions
- to_value() returns a value of a specified type that is static_cast from the named type's value.
- container_cast() returns a reference to a specified vector of named type as a vector of the named type's value type.