Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion docs/design/tuple.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<looking_for<type>, in_tuple<Ts...>>,
"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<T, Ts...> : tuple<Ts...> {
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`

Expand Down
42 changes: 42 additions & 0 deletions docs/design/type_traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<type_traits>` while `to_underlying`
is in `<utility>`. `stdx` puts both in `<type_traits>`.

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 `<type_traits.hpp>`. Each class that specializes them then includes
`<type_traits.hpp>` rather than `<tuple.hpp>`.

## `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.
73 changes: 37 additions & 36 deletions docs/header_graph.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ flowchart BT
array(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/array.hpp">array.hpp</a>)
atomic(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/atomic.hpp">atomic.hpp</a>)
ct_conversions(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ct_conversions.hpp">ct_conversions.hpp</a>)
priority(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/priority.hpp">priority.hpp</a>)
numeric(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/numeric.hpp">numeric.hpp</a>)
array ~~~ compiler
atomic ~~~ compiler
ct_conversions --> compiler
priority(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/priority.hpp">priority.hpp</a>)
numeric(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/numeric.hpp">numeric.hpp</a>)
priority ~~~ compiler
numeric ~~~ compiler

Expand All @@ -20,85 +20,86 @@ flowchart BT

%% level 3
iterator(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/iterator.hpp">iterator.hpp</a>)
iterator --> type_traits
concepts(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/concepts.hpp">concepts.hpp</a>)
concepts --> type_traits
udls(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/udls.hpp">udls.hpp</a>)
function_traits(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/function_traits.hpp">function_traits.hpp</a>)
iterator --> type_traits
concepts --> type_traits
function_traits --> type_traits

%% level 4
cx_vector(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_vector.hpp">cx_vector.hpp</a>)
rollover(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/rollover.hpp">rollover.hpp</a>)
utility(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/utility.hpp">utility.hpp</a>)
cx_vector --> iterator
cx_vector --> concepts
rollover(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/rollover.hpp">rollover.hpp</a>)
rollover --> concepts
utility(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/utility.hpp">utility.hpp</a>)
utility --> concepts
utility --> udls

%% level 5
cx_map(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_map.hpp">cx_map.hpp</a>)
bit(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/bit.hpp">bit.hpp</a>)
ct_string(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ct_string.hpp">ct_string.hpp</a>)
tuple(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple.hpp">tuple.hpp</a>)
cx_map ---> iterator
cx_map --> utility
bit(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/bit.hpp">bit.hpp</a>)
bit --> utility
ct_string(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ct_string.hpp">ct_string.hpp</a>)
ct_string --> utility
tuple(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple.hpp">tuple.hpp</a>)
tuple --> utility

%% level 6
span(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/span.hpp">span.hpp</a>)
byterator(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/byterator.hpp">byterator.hpp</a>)
cx_set(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_set.hpp">cx_set.hpp</a>)
bitset(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/bitset.hpp">bitset.hpp</a>)
panic(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/panic.hpp">panic.hpp</a>)
env(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/env.hpp">env.hpp</a>)
functional(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/functional.hpp">functional.hpp</a>)
C(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/algorithm.hpp">algorithm.hpp</a><br><a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple_destructure.hpp">tuple_destructure.hpp</a>)
for_each_n_args(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/for_each_n_args.hpp">for_each_n_args.hpp</a>)

%% level 7
cx_multimap(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_multimap.hpp">cx_multimap.hpp</a>)
cx_queue(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_queue.hpp">cx_queue.hpp</a>)
atomic_bitset(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/atomic_bitset.hpp">atomic_bitset.hpp</a>)
B(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/intrusive_forward_list.hpp">intrusive_forward_list.hpp<br><a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/intrusive_list.hpp">intrusive_list.hpp</a>)
pp_map(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/pp_map.hpp">pp_map.hpp</a>)
ranges(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ranges.hpp">ranges.hpp</a>)
tuple_algorithms(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple_algorithms.hpp">tuple_algorithms.hpp</a>)
ct_format(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ct_format.hpp">ct_format.hpp</a>)
call_by_need(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/call_by_need.hpp">call_by_need.hpp</a>)
latched(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/latched.hpp">latched.hpp</a>)
optional(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/optional.hpp">optional.hpp</a>)

%% level 8
cached(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cached.hpp">cached.hpp</a>)
static_assert(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/static_assert.hpp">static_assert.hpp</a>)

span ----> iterator
span --> bit
byterator(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/byterator.hpp">byterator.hpp</a>)
byterator --> bit
cx_set(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_set.hpp">cx_set.hpp</a>)
cx_set ---> cx_map
bitset(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/bitset.hpp">bitset.hpp</a>)
bitset --> bit
bitset --> ct_string
panic(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/panic.hpp">panic.hpp</a>)
panic --> ct_string
env(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/env.hpp">env.hpp</a>)
env --> ct_string
tuple_algorithms(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple_algorithms.hpp">tuple_algorithms.hpp</a>)
tuple_algorithms --> tuple
functional(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/functional.hpp">functional.hpp</a>)
functional --> tuple
C(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/algorithm.hpp">algorithm.hpp</a><br><a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/tuple_destructure.hpp">tuple_destructure.hpp</a>)
C --> tuple
for_each_n_args(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/for_each_n_args.hpp">for_each_n_args.hpp</a>)
for_each_n_args ----> function_traits
for_each_n_args --> tuple

%% level 7
cx_multimap(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_multimap.hpp">cx_multimap.hpp</a>)
cx_multimap --> cx_set
cx_queue(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cx_queue.hpp">cx_queue.hpp</a>)
cx_queue ----> iterator
cx_queue --> panic
atomic_bitset(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/atomic_bitset.hpp">atomic_bitset.hpp</a>)
atomic_bitset ---> bitset
B(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/intrusive_forward_list.hpp">intrusive_forward_list.hpp<br><a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/intrusive_list.hpp">intrusive_list.hpp</a>)
B --> panic
pp_map(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/pp_map.hpp">pp_map.hpp</a>)
ranges(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ranges.hpp">ranges.hpp</a>)
call_by_need(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/call_by_need.hpp">call_by_need.hpp</a>)
call_by_need --> tuple_algorithms
ct_format(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/ct_format.hpp">ct_format.hpp</a>)
ct_format ---> ct_string
ct_format --> tuple_algorithms
ct_format --> pp_map
ct_format --> ranges
latched(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/latched.hpp">latched.hpp</a>)
ct_format --> tuple_algorithms
call_by_need --> tuple_algorithms
latched --> functional
optional(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/optional.hpp">optional.hpp</a>)
optional --> functional

%% level 8
cached(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/cached.hpp">cached.hpp</a>)
cached --> latched
static_assert(<a href="https://github.com/intel/cpp-std-extensions/tree/main/include/stdx/static_assert.hpp">static_assert.hpp</a>)
static_assert --> ct_format