diff --git a/docs/design/tuple.md b/docs/design/tuple.md index ffc74c7..bd517ae 100644 --- a/docs/design/tuple.md +++ b/docs/design/tuple.md @@ -16,8 +16,44 @@ the resulting pairs to pull the elements from each input tuple. `stdx::tuple` is a basic dependency for many things; for that reason `tuple.hpp` doesn't include very much, and in particular must avoid circular dependencies. + For example, it can't use formatted `static_assert`s (because they make use of -`tuple`). +`tuple`). The diagnostics emitted when `get` fails to compile are helped by +suitable type names in the `stdx::error` namespace: + +```cpp +static_assert(always_false_v, in_tuple>, + "Type not found in tuple!"); +``` + +## Constructors + +There are a couple of basic ways of implementing tuple. The standard uses +recursion like this (sketch): + +``` +struct tuple : tuple { + T element; +}; +``` + +This means that the actual layout of the elements is "in reverse", because the +first element is in the `struct` that inherits from all the rest, etc. This also +means that `std::tuple` has many complex constructors. + +`stdx::tuple` uses the other way: tag each type with an index (this is necessary +for uniqueness, so that we can have repeated types in the tuple) and inherit +from the expanded pack of such elements. + +This means the layout is in order, and the rule of zero can apply. To ease the +construction, we turn off `-Wmissing-braces` so that we can write: + +```cpp +auto t = stdx::tuple{1, 2, 3}; +``` + +and the compiler doesn't complain about brace elision (otherwise it would want +us to write e.g. `stdx::tuple{{1}, {2}, {3}}`). ## `tuplelike` vs `has_tuple_protocol` diff --git a/docs/design/type_traits.md b/docs/design/type_traits.md index afe6810..b3cd6ad 100644 --- a/docs/design/type_traits.md +++ b/docs/design/type_traits.md @@ -19,3 +19,45 @@ operations are done through alias templates, which are much cheaper. STL implementations typically do the same thing for internal use, but the standard constrains them to provide the more expensive interface. +## `to_underlying` + +In the standard, `underlying_type_t` is in `` while `to_underlying` +is in ``. `stdx` puts both in ``. + +In the standard, this fails to compile: + +```cpp +auto x = to_underlying(42); +``` + +because `to_underlying` is defined only on enumeration types. But in practice, +it is very useful in generic code to have an "idempotent" form of +`to_underlying` that reduces an enumeration to the underlying integral type and +is a no-op otherwise. That's what `stdx::to_underlying` does. + +### Other ideas + +`stdx::to_underlying` could be constrained to work on either integral or +enumeration types, but it is currently unconstrained. + +## Tuple helpers + +The standard seems ambiguous on where the primary template declarations for +`tuple_element` and `tuple_size` are to be kept, or if it matters. We choose to +put them in ``. Each class that specializes them then includes +`` rather than ``. + +## `type_identity` + +`std::type_identity` and `std::type_identity_t` exist from C++20, so in theory +we could get rid of their counterparts in `stdx`. However, the standard does not +define `type_identity_v` -- which is actually very useful. Given that utility, +it is consistent to provide all three in `stdx`; especially given that they are +trivial. + +## Miscellaneous + +We expect to remove several type traits from `stdx` as standard adoption allows. + +`is_specialization_of` and `is_same_template_v` get a lot easier particularly +with reflection. diff --git a/docs/header_graph.mmd b/docs/header_graph.mmd index 7867ed4..6663afb 100644 --- a/docs/header_graph.mmd +++ b/docs/header_graph.mmd @@ -6,11 +6,11 @@ flowchart BT array(array.hpp) atomic(atomic.hpp) ct_conversions(ct_conversions.hpp) + priority(priority.hpp) + numeric(numeric.hpp) array ~~~ compiler atomic ~~~ compiler ct_conversions --> compiler - priority(priority.hpp) - numeric(numeric.hpp) priority ~~~ compiler numeric ~~~ compiler @@ -20,85 +20,86 @@ flowchart BT %% level 3 iterator(iterator.hpp) - iterator --> type_traits concepts(concepts.hpp) - concepts --> type_traits udls(udls.hpp) function_traits(function_traits.hpp) + iterator --> type_traits + concepts --> type_traits function_traits --> type_traits %% level 4 cx_vector(cx_vector.hpp) + rollover(rollover.hpp) + utility(utility.hpp) cx_vector --> iterator cx_vector --> concepts - rollover(rollover.hpp) rollover --> concepts - utility(utility.hpp) utility --> concepts utility --> udls %% level 5 cx_map(cx_map.hpp) + bit(bit.hpp) + ct_string(ct_string.hpp) + tuple(tuple.hpp) cx_map ---> iterator cx_map --> utility - bit(bit.hpp) bit --> utility - ct_string(ct_string.hpp) ct_string --> utility - tuple(tuple.hpp) tuple --> utility %% level 6 span(span.hpp) + byterator(byterator.hpp) + cx_set(cx_set.hpp) + bitset(bitset.hpp) + panic(panic.hpp) + env(env.hpp) + functional(functional.hpp) + C(algorithm.hpp
tuple_destructure.hpp) + for_each_n_args(for_each_n_args.hpp) + + %% level 7 + cx_multimap(cx_multimap.hpp) + cx_queue(cx_queue.hpp) + atomic_bitset(atomic_bitset.hpp) + B(intrusive_forward_list.hpp
intrusive_list.hpp) + pp_map(pp_map.hpp) + ranges(ranges.hpp) + tuple_algorithms(tuple_algorithms.hpp) + ct_format(ct_format.hpp) + call_by_need(call_by_need.hpp) + latched(latched.hpp) + optional(optional.hpp) + + %% level 8 + cached(cached.hpp) + static_assert(static_assert.hpp) + span ----> iterator span --> bit - byterator(byterator.hpp) byterator --> bit - cx_set(cx_set.hpp) cx_set ---> cx_map - bitset(bitset.hpp) bitset --> bit bitset --> ct_string - panic(panic.hpp) panic --> ct_string - env(env.hpp) env --> ct_string - tuple_algorithms(tuple_algorithms.hpp) tuple_algorithms --> tuple - functional(functional.hpp) functional --> tuple - C(algorithm.hpp
tuple_destructure.hpp) C --> tuple - for_each_n_args(for_each_n_args.hpp) for_each_n_args ----> function_traits for_each_n_args --> tuple - - %% level 7 - cx_multimap(cx_multimap.hpp) cx_multimap --> cx_set - cx_queue(cx_queue.hpp) cx_queue ----> iterator cx_queue --> panic - atomic_bitset(atomic_bitset.hpp) atomic_bitset ---> bitset - B(intrusive_forward_list.hpp
intrusive_list.hpp) B --> panic - pp_map(pp_map.hpp) - ranges(ranges.hpp) - call_by_need(call_by_need.hpp) - call_by_need --> tuple_algorithms - ct_format(ct_format.hpp) ct_format ---> ct_string - ct_format --> tuple_algorithms ct_format --> pp_map ct_format --> ranges - latched(latched.hpp) + ct_format --> tuple_algorithms + call_by_need --> tuple_algorithms latched --> functional - optional(optional.hpp) optional --> functional - - %% level 8 - cached(cached.hpp) cached --> latched - static_assert(static_assert.hpp) static_assert --> ct_format