Why is tuple_size
a free trait and not a member variables/typedefs within the class? The latter has a much smaller risk of causing ODR violations.
Is there a concrete use case where having a trait tuple_size
is better than defining this inline within the class? Is there a motivating case similar to that of iterator_traits
(https://stackoverflow.com/a/6742025/5501675) The only one I see is the benefit it brings with incomplete types. Though not entirely sure what a use case for that is
tuple_size
could easily be made a member something like this
class Something {
public:
static constexpr auto tuple_size = 3;
};
And then the free implementation of the tuple_size
trait can be
template <typename T, EnableIfHasTupleSize<std::decay_t<T>>* = nullptr>
struct tuple_size
: public std::integral_constant<std::size_t,
std::decay_t<T>::tuple_size>
{};
Such an implementation would bring both the benefits of having a tuple_size
that can work with incomplete types if specialized as well as offering the security of the member constant where needed. Similar to iterator_traits
This example was given to me by @T.C. recently of how tuple_size can easily cause ODR violations.
struct X { int a; };
template<> struct std::tuple_size<X>;
template<size_t I> struct std::tuple_element<I, X> { using type = int; };
template<size_t I> int get(X) { return 1; }
call_func_that_checks_value_of_tuple_size(X{});
template<> struct std::tuple_size<X> : std::integral_constant<size_t, 3> {};
call_func_that_checks_value_of_tuple_size(X{});
Compilers are able to pick up on this, however if this is split between translation units, its very hard for a compiler to catch this.
In C++17 structured bindings require that a type support
std::tuple_size<T>
, ADL-enabledget<std::size_t>
, andstd::tuple_element<std::size_t, T>
.If a type supports all 3, structured binding works.
This permits you to take a type provided by a 3rd party, like QPair, and without modifying their source code or requiring them to update, use it in a structured binding way in your code.
If
tuple_size
was a member oftuple
(andarray
andpair
), then we would have had to add atuple_size
trait in C++17 to have this capability anyhow.