Pourquoi tuple_size
est-il un trait libre et non un membre/variable/typedefs dans la classe? Ce dernier a un risque beaucoup plus faible de provoquer des violations ODR.Pourquoi tuple_size est-il un trait et non un membre
Existe-t-il un cas d'utilisation concret où avoir un trait tuple_size
est mieux que de définir cette ligne dans la classe? Y a-t-il un cas motivant semblable à celui de iterator_traits
(https://stackoverflow.com/a/6742025/5501675) Le seul que je vois est le bénéfice qu'il apporte avec les types incomplets. Bien que pas tout à fait sûr de ce qu'un cas d'utilisation pour c'est
tuple_size
pourrait facilement être fait une chose membre comme celui-ci
class Something {
public:
static constexpr auto tuple_size = 3;
};
Et puis la mise en œuvre libre du trait tuple_size
peut être
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>
{};
Une telle implémentation apporterait à la fois les avantages d'avoir un tuple_size
qui peut fonctionner avec des types incomplets si spécialisés ainsi que d'offrir la sécurité de la constante membre si nécessaire. Similaire à iterator_traits
Cet exemple m'a été donné par @T.C. récemment de la façon dont tuple_size peut facilement causer des violations ODR.
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{});
sont Compilateurs en mesure de prendre à ce sujet, si cela est réparti entre les unités de traduction, il est très difficile pour un compilateur pour attraper ce.