Contents
- Example usage
- In a nutshell
- License
- Dependencies
- Installation
- Synopsis
- Reported to work with
- Building the tests
- Other implementations of strong types
- Notes and references
- Appendix
#include "nonstd/type.hpp"
typedef nonstd::ordered<int, struct day_tag , nonstd::no_default_t> Day;
typedef nonstd::ordered<int, struct year_tag, nonstd::no_default_t> Year;
enum Month
{
January=1, February, March, April, May, June,
July, August, September, October, November, December
};
class Date
{
public:
Date( Year year, Month month, Day day ) {}
// ...
};
int main()
{
auto date = Date( Year(2018), July, Day(21) ); // OK
// date = Date( 2018, July, 21 ); // compile-time error
// date = Date( Day(21), July, Year(2018) ); // compile-time error
// date = Date( July, Day(21), Year(2018) ); // compile-time error
}
prompt> g++ -Wall -std=c++11 -I../include -o 01-basic 01-basic.cpp && ./01-basic
type lite provides building blocks to create strong types with, such as bits
, numeric
, quantity
and address
.
Features and properties of type are ease of installation (single header), freedom of dependencies other than the standard library.
type lite is distributed under the Boost Software License.
type lite has no other dependencies than the C++ standard library.
type lite is a single-file header-only library. Here are some ways to use it:
- As copied header in the include folder of the project source tree or somewhere reachable from your project.
- As copied header used from CMake
- As external Git project
- As CMake package
- As Conan package
Contents
- Namespace and types
- Create a default-constructible type
- Create a default-constructible type with a custom value
- Create a non-default-constructible type
- Create a sub-type
- Define a function taking a strong type
- Define a streaming operator for strong types
- Table with types, their operations and free functions and macros
Types and functions of type lite are in namespace nonstd
.
With the exception of boolean
, types type
bits
, logical
, equality
, ordered
, numeric
, quantity
, address
, offset
are declared as:
template< typename T, typename Tag, typename D = T >
struct type;
With boolean
declared as:
template< typename Tag, typename D = bool >
struct boolean;
Type type
is the (possibly indirect) base class of the other strong types.
Declaring default-constructible type Quantity (example code):
typedef nonstd::quantity<double, struct QuantityTag> Quantity;
Using the macro:
type_DEFINE_TYPE( Quantity, quantity, double )
Declaring default-constructible type Index with a non-zero default value (example code):
typedef nonstd::equality<size_t, struct IndexTag,
nonstd::custom_default_t<size_t, std::numeric_limits<size_t>::max()> > Index;
Using the macro:
type_DEFINE_TYPE_CD( Index, equality, size_t, std::numeric_limits<size_t>::max() )
Declaring non-default-constructible type Ordered (example code):
typedef nonstd::ordered<int, struct OrderedTag, nonstd::no_default_t> Ordered;
Using the macro:
type_DEFINE_TYPE_ND( Ordered, ordered, int )
To enable the creation of operations that are common to different types, type lite allows to create sub types (example code):
type_DEFINE_SUBTYPE( Current, Quantity )
type_DEFINE_SUBTYPE( Voltage, Quantity )
type_DEFINE_SUBTYPE_ND( Day , Ordered )
type_DEFINE_SUBTYPE_ND( Year, Ordered )
Please be aware that this allows undesired mixed expressions like Current(7) + Voltage(42)
and Day(21) < Year(2019)
.
Defining a (constexpr) function taking strong type (example code):
type_DEFINE_TYPE( Integer, numeric, int )
type_DEFINE_FUNCTION( Integer, abs, std::abs )
type_DEFINE_FUNCTION_CE( Integer, abs_ce, std::abs )
With the following stream operator, any strong type of type lite can be output (example code):
template< typename T, typename Tag, typename D >
inline std::ostream & operator<<( std::ostream & os, nonstd::type<T,Tag,D> const & v )
{
return os << "[type:" << v.get() << "]";
}
Kind | Std | Operations / remarks |
---|---|---|
Types | ||
type | no operations; base class of the following types | |
bits | ~ & ¦ ^ << >> &= ¦= ^= <<= >>= | |
boolean | explicit bool conversion, see note 1 | |
logical | ! && ¦¦ | |
equality | == != | |
ordered | equality < <= >= > | |
numeric | ordered unary+ unary- ++ -- + - / % += -= = /= %= | |
quantity | ordered unary+ unary- + - / += -= = /= with q / q → T T × q q × T q / T |
|
offset | ordered o + o o - o o += o o -= o | |
address | ordered a - a a + o a - o a += o a -= o | |
no_default_t | used to make type non-default-constructible | |
custom_default_t | used to specify a custom value for default construction | |
std::hash<type<...>> | C++11 | hash type for type in namespace std ; see make_hash() |
Free functions | ||
make_hash() | C++11 | create hash value for an object of strong type |
swap() | swap two strong type objects | |
to_value() | convert strong type object to underlying value | |
[operator<<] | [not provided] | |
Macros | ||
type_DECLARE_TAG | C++98 | Declare tag S_tag for strong type S to prevent warning "uses local type" in C++98 |
type_DEFINE_TYPE | Define a default-constructible strong typeS , based on type , implementation type T |
|
type_DEFINE_TYPE_CD | Define a custom-default-constructible strong typeS , based on type , implementation type T , default value V |
|
type_DEFINE_TYPE_ND | Define a non-default-constructible strong typeS , based on type , implementation type T |
|
type_DEFINE_SUBTYPE | Define a default-constructible subtype U of strong type S |
|
type_DEFINE_SUBTYPE_ND | Define a non-default-constructible subtype U of strong type S |
|
type_DEFINE_FUNCTION | Adapt an existing function f for strong type S |
|
type_DEFINE_FUNCTION_CE | Adapt an existing constexpr function f for strong type S |
Note 1: On Windows, completely specify nonstd::boolean
to prevent clashing with boolean
from Windows SDK rpcndr.h
There are no configuration flags currently.
The table below mentions the compiler versions type lite is reported to work with.
OS | Compiler | Where | Versions |
---|---|---|---|
GNU/Linux | Clang/LLVM | Travis | 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0 |
GCC | Travis | 4.8, 4.9, 5, 6, 7, 8 | |
OS X | Xcode | Travis | 7.3, 8, 9, 10 |
Windows | Clang/LLVM | Local | 8.0 |
GCC | Local | 8.1 | |
Visual C++ (Visual Studio) |
Local AppVeyor |
10 (2010), 11 (2012), 12 (2013), 14 (2015) non 64-bit, 15 (2017) 10 (2010), 11 (2012), 12 (2013), 14 (2015) non 64-bit, 15 (2017) |
|
DOSBox | DJGPP | Local | ? |
FreeDOS | DJGPP | Local | ? |
To build the tests you need:
- CMake, version 3.0 or later to be installed and in your PATH.
- A suitable compiler.
The lest test framework is included in the test folder.
The following steps assume that the type lite source code has been cloned into a directory named ./type
.
-
Create a directory for the build outputs.
cd ./type md build && cd build
-
Configure CMake to use the compiler of your choice (run
cmake --help
for a list).cmake -G "Unix Makefiles" -DTYPE_LITE_OPT_BUILD_TESTS=ON ..
-
Build the test suite.
cmake --build .
-
Run the test suite.
ctest -V
All tests should pass, indicating your platform is supported and you are ready to use type lite.
- Anthony Williams. strong_typedef on GitHub, since 2019.
- Björn Fahller. strong_type on GitHub, since 2017.
- Tony van Eerd. StrongId on GitHub, since 2017.
- Jonathan Boccara. NamedType on GitHub, since 2017.
- Jonathan Müller. type_safe on GitHub, since 2016.
- Vicente J. Botet Escriba. std-make strong on GitHub since 2017.
- Martin Moene. WholeValue on GitHub, since 2012.
- Boost.Serialization. Boost Strong Typedef. Boost 1.61.0.
Blogs
- Jonathan Boccara. Strong types for strong interfaces. 8 December 2016.
- Jonathan Müller. Tutorial: Emulating strong/opaque typedefs in C++. 19 Oct 2016.
- Andrzej Krzemieński. Declaring the move constructor. 11 September 2015.
- Andrzej Krzemieński. noexcept — what for?. 24 April 2014.
Presentations
- Björn Fahller. Type Safe C++? - LOL! :-). ACCU 2018.
- Jonathan Boccara. Strong types for strong interfaces. Meeting C++ 2017.
- Kyle Markley. Extreme Type Safety with Opaque Typedefs. CppCon 2015.
Proposals
- Walter E. Brown. N3741 - Toward Opaque Typedefs for C++1Y, v2. 30 August 2013.
The version of type lite is available via tag [.version]
. The following tags are available for information on the compiler and on the C++ standard library used: [.compiler]
, [.stdc++]
, [.stdlanguage]
and [.stdlibrary]
.
click to expand
type: Disallows to default-construct a type thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
type: Allows to default-construct a type thus defined
type: Allows to custom-default-construct a type thus defined
type: Allows to copy-construct a type from its underlying type
type: Allows to move-construct a type from its underlying type (C++11)
type: Allows to copy-construct a type
type: Allows to move-construct a type (C++11)
type: Allows to copy-assign a type
type: Allows to move-assign a type (C++11)
type: Allows to copy-swap a type
type: Allows to move-swap a type (C++11)
type: Allows to obtain hash of a type object (C++11)
boolean: Disallows to default-construct a boolean thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
boolean: Disallows to substitute booleans with different tags (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
boolean: Allows to default-construct a boolean thus defined
boolean: Allows to custom-default-construct a boolean thus defined
boolean: Allows to copy-construct a boolean from its underlying type
boolean: Allows explicit conversion to a native bool
boolean: Allows to negate a boolean
boolean: Allows to compare a boolean for equality
boolean: Allows to obtain hash of a boolean object (C++11)
logical: Disallows to default-construct a logical thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
logical: Allows to default-construct a logical thus defined
logical: Allows to custom-default-construct a logical thus defined
logical: Allows to copy-construct a logical from its underlying type
logical: Allows to move-construct a logical from its underlying type (C++11)
logical: Allows to negate a logical
logical: Allows to and two logicals
logical: Allows to or two logicals
logical: Allows to obtain hash of a logical object (C++11)
equality: Disallows to default-construct an equality thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
equality: Allows to default-construct an equality thus defined
equality: Allows to custom-default-construct a equality thus defined
equality: Allows to copy-construct an equality from its underlying type
equality: Allows to move-construct an equality from its underlying type (C++11)
equality: Allows to compare an equality for equality
equality: Allows to obtain hash of an equality object (C++11)
bits: Disallows to default-construct a bits thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
bits: Allows to default-construct a bits thus defined
bits: Allows to custom-default-construct a bits thus defined
bits: Allows to copy-construct a bits from its underlying type
bits: Allows to move-construct a bits from its underlying type (C++11)
bits: Allows to compare bits for equality
bits: Allows to negate bits
bits: Allows to and bits
bits: Allows to or bits
bits: Allows to xor bits
bits: Allows to shift-left bits
bits: Allows to shift-right bits
bits: Allows to obtain hash of a bits object (C++11)
ordered: Disallows to default-construct an ordered thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
ordered: Allows to default-construct an ordered thus defined
ordered: Allows to custom-default-construct an ordered thus defined
ordered: Allows to copy-construct an ordered from its underlying type
ordered: Allows to move-construct an ordered from its underlying type (C++11)
ordered: Allows to compare an ordered for equality
ordered: Allows to compare an ordered for order
ordered: Allows to obtain hash of an ordered object (C++11)
numeric: Disallows to default-construct a numeric thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
numeric: Allows to default-construct a numeric thus defined
numeric: Allows to custom-default-construct a numeric thus defined
numeric: Allows to copy-construct a numeric from its underlying type
numeric: Allows to move-construct a numeric from its underlying type (C++11)
numeric: Allows to compare a numeric for equality
numeric: Allows to compare a numeric for order
numeric: Allows to apply unary+, unary-
numeric: Allows to apply pre- and post-increment and -decrement
numeric: Allows to add, subtract, multiply, divide, rest-divide numerics (x op y)
numeric: Allows to add, subtract, multiply, divide, rest-divide numerics (x op= y)
numeric: Allows to obtain hash of a numeric object (C++11)
quantity: Disallows to default-construct a quantity thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
quantity: Allows to default-construct a quantity thus defined
quantity: Allows to custom-default-construct a quantity thus defined
quantity: Allows to copy-construct a quantity from its underlying type
quantity: Allows to move-construct a quantity from its underlying type (C++11)
quantity: Allows to compare a numeric for equality
quantity: Allows to compare a numeric for order
quantity: Allows to apply unary+, unary-
quantity: Allows to add, subtract quantities (x op y)
quantity: Allows to add, subtract quantities (x op= y)
quantity: Disallows to multiply a quantity with a quantity
quantity: Allows to multiply a quantity with a scalar (result: quantity)
quantity: Allows to divide a quantity by a scalar (result: quantity)
quantity: Allows to divide a quantity by a quantity (result: scalar)
quantity: Allows to obtain hash of a quantity object (C++11)
address: Disallows to default-construct an address thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
address: Allows to default-construct an address thus defined
address: Allows to custom-default-construct a address thus defined
address: Allows to copy-construct an address from its underlying type
address: Allows to move-construct an address from its underlying type (C++11)
address: Disallows to add addresses
address: Allows to subtract addresses to yield an offset (a - a)
address: Allows to add, subtract an offset (a + o, a - o)
address: Allows to add, subtract an offset (a += o, a -= o)
address: Allows to an offset and an addresses (a + o, o + a)
address: Allows to subtract an offset from an address (a - o)
address: Disallows to subtract an addresses from an offset
address: Allows to obtain hash of an address object (C++11)
offset: Disallows to default-construct an offset thus defined (define type_CONFIG_CONFIRMS_COMPILATION_ERRORS)
offset: Allows to default-construct an offset thus defined
offset: Allows to custom-default-construct a offset thus defined
offset: Allows to copy-construct an offset from its underlying type
offset: Allows to move-construct an offset from its underlying type (C++11)
offset: Allows to add, subtract offsets (x op y)
offset: Allows to add, subtract offsets (x op= y)
offset: Allows to obtain hash of an offset object (C++11)
macro: type_DEFINE_TYPE(Strong, type, native)
macro: type_DEFINE_TYPE_CD(Strong, type, native, value)
macro: type_DEFINE_TYPE_ND(Strong, type, native)
macro: type_DEFINE_SUBTYPE(Sub, Super)
macro: type_DEFINE_SUBTYPE_ND(Sub, Super)
macro: type_DEFINE_FUNCTION(Strong, StrongFunction, function)
macro: type_DEFINE_FUNCTION_CE(Strong, StrongFunction, function)