Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is tuple_size a trait and not a member

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.

like image 725
Curious Avatar asked Oct 25 '25 07:10

Curious


1 Answers

In C++17 structured bindings require that a type support std::tuple_size<T>, ADL-enabled get<std::size_t>, and std::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 of tuple (and array and pair), then we would have had to add a tuple_size trait in C++17 to have this capability anyhow.

like image 163
Yakk - Adam Nevraumont Avatar answered Oct 26 '25 21:10

Yakk - Adam Nevraumont