This library contains:
- opaque typedef's –
explicit_type
; - tuple indexed by type, instead of standard numeric-index based –
type_tuple
.
Library's elements are fully constexpr
(or partially when using with C++11)
Standard, index-based tuples requires us to remember or constantly checking out what specific index stands for. Let's see an example:
using db_options = std::tuple<bool /*auto_commit*/, bool /*use_cache*/, int /*cache_size*/>;
//usage:
db_options options{false, true, 500};
auto db = open_db(options);
This example is pretty ugly as passing list of raw values to function causes poorly readable code. Of course in this particular example we would rather develop a structure containing database options. Possibly the best option would be to use named parameters. Unfortunately C++ itself does not handle that feature. Please note that very similar (but not the same) feature comes with C++20's designated initializers.
Let's see the example with database, rewritten using type_tuple
library:
using use_cache = mj::explicit_type<bool, class use_cache_tag>;
using cache_size = mj::explicit_type<int, class cache_size_tag>;
using auto_commit = mj::explicit_type<bool, class auto_commit_tag>;
using db_options = mj::type_tuple<use_cache, cache_size, auto_commit>;
//usage:
db_options options{auto_commit{false}, cache_size{500}, use_cache{true}};
auto db = open_db(options);
Let's see what happens here.
At first, we declare each option type.
All of those has unique tag at template parameter list, just to make each of them having unique types.
Then we declare the tuple itself. The type_tuple
is a variadic template, but – unlike std::tuple
all types have to be unique.
What for? We can see the answer when we see the tuple usage. The constructor arguments are binded by a type, not by an order.
This means that all of following statements are the same:
db_options options{auto_commit{false}, cache_size{500}, use_cache{true}};
db_options options{auto_commit{false}, use_cache{true}, cache_size{500}};
db_options options{cache_size{500}, auto_commit{false}, use_cache{true}};
db_options options{cache_size{500}, use_cache{true}, auto_commit{false}};
db_options options{use_cache{true}, cache_size{500}, auto_commit{false}};
db_options options{use_cache{true}, auto_commit{false}, cache_size{500}};
What is more, we don't have to set every value, but just leave it default-constructed:
db_options options{auto_commit{true}};
assert(0 == options.get<cache_size>());
assert(false == options.get<use_cache>());
this example also shows the getter usage.
This library is not a "better tuple" and never will be.
The definition of such tuple is more complicated, and are considered to be used in very different contexts.
The first idea of name of this library was properties
,
as it was needed for setting properties for initialization of some other libraries in more expressive way.
So this is rather a hacky workaround for lack of named parameters feature in C++ language.
The explicit_type
purpose is very similar to BOOST_STRONG_TYPEDEF.
Is it that bad? Boost libraries widely uses macros so I will not give you an answer, just refer to Bjarne Stroustrup thoughts about using macros.
Please note that also designated initializers from C++20 functionality differs from this libraries purposes – it doesn't support mixed order of parameters, it's also limited to an object constructors so no appliable to a ordinary functions/member functions whereas this library could be applied to variadic templated functions.
explicit_type
doesn't support arrays (and probably never will, usestd::array
instead)explicit_type
doesn't support references (TO ANALYSE)- default values for parameter is always default-constructed (TODO)
- it is early version of it, so a bug can happen (please inform me)
It is a C++11 header-only library. Requires C++11 support
Distributed under the Boost Software License, Version 1.0.
This library was inspired by Andrzej Krzemieński's explicit
library, especially tagged_bool
part of it and is extension of the idea.