How is it possible to get the largest member of template parameter pack?

Viewed 199

My struct is defined like this:

template<class...T> struct Data {};

How is it possible to get the maximum of sizeof(T), so it can be used inside struct Data?

3 Answers

If you need the largest size, the solution is pretty straightforward: use std::max overload that takes std::initializer_list. It is constexpr since C++14.

constexpr std::size_t max_size = std::max({sizeof(T)...});

To handle an empty pack you might add the 0 argument:

constexpr std::size_t max_size = std::max({0, sizeof(T)...});

If the type itself is needed and Boost can be used, Boost.Mp11 might help:

namespace mp11 = boost::mp11;

template<class T1, class T2>
struct less_sizeof : mp11::mp_bool<(sizeof(T1) < sizeof(T2))> {};

using Tm = mp11::mp_max_element<mp11::mp_list<T...>, less_sizeof>;

If Boost is not available, some simple metaprogramming could be used:

template<class T, class... U>
struct max_sizeof {
    using Tm = typename max_sizeof<U...>::type;
    using type = std::conditional_t<(sizeof(Tm) < sizeof(T)), T, Tm>;
};

template<class T>
struct max_sizeof<T> {
    using type = T;
};

using Tm = typename max_sizeof<Ts...>::type;

In both cases a tie is resolved to the last type with the largest sizeof(T).

If you want the actual type (well, the first type that has the maximum size) then it can be pretty compact in C++17 and beyond:

#include <cstddef>
#include <algorithm>
#include <tuple>

template<class...T> struct Data {

    static constexpr std::size_t biggest_idx() {
        std::size_t const sizes[] { sizeof(T) ... };
        return std::max_element(std::begin(sizes), std::end(sizes)) - std::begin(sizes);
    }
    
    using biggest = std::tuple_element_t<biggest_idx(), std::tuple<T...>>;
};

Just find the index in a constexpr utility (with the constexpr max_element), and then use the std::tuple facilitates to obtain the type.

If you don't like using std::tuple here, then you can roll your own meta-function of course. Pretty straight-forward. You can also write the loop for finding the maximum index by hand if you only have C++14.

Works for >= C++14 (assuming you want the type with the largest size and not the largest size itself):

#include <algorithm>
#include <type_traits>

template <typename T, typename ...Ts>
struct largest_type
{
    using type = typename std::conditional<
        sizeof (T) == std::max({sizeof (T), sizeof (Ts)...}),
        T,
        typename largest_type<Ts...>::type
    >::type;
};

template <typename T>
struct largest_type<T>
{
    using type = T;
};

template <typename T, typename ...Ts>
using largest_type_t = typename largest_type<T, Ts...>::type;

static_assert(std::is_same<largest_type_t<int, char, long>, long>::value, "");
Related