Проблемы вашего первоначального подхода должным образом объяснены в Ответ Окталиста .
Обратите внимание, что size_of_tuple
может быть реализовано в одну строку с использованием C ++ 17 выражений сгиба :
template<class... Ts>
constexpr std::size_t size_of_tuple(const std::tuple<Ts...>&) {
return (0 + ... + sizeof(Ts));
}
Однако эту функцию сложно использовать из-за аргумента типа const std::tuple<Ts...>&
.Таким образом, может быть желательно ввести пустой тип тега, который может быть «передан» этим метафункциям.Эта идея объясняется в главе Boost.Hana
о вычислениях типов .
Ниже приведен полный пример.
static_assert(__cplusplus >= 201703L, "C++17 required");
#include <cstddef>
#include <cstdint>
#include <tuple>
// the empty tag type
template<class T>
struct Type {};
////////////////////////////////////////////////////////////////////////////////
template<class... Ts>
constexpr std::size_t size_of_tuple(Type< std::tuple<Ts...> >) {
return (0 + ... + sizeof(Ts));
}
static_assert(0 == size_of_tuple(Type< std::tuple<> >{}));
static_assert(12 == size_of_tuple(Type< std::tuple<int32_t, int64_t> >{}));
static_assert(12 == size_of_tuple(Type< std::tuple<int32_t&, int64_t&> >{}));
static_assert(2 == size_of_tuple(Type< std::tuple<char&, char> >{}));
static_assert(6 == size_of_tuple(Type< std::tuple<int32_t&, char&, char> >{}));
// fails to compile (for good reasons):
//static_assert(8 == size_of_tuple(Type< std::tuple<int32_t, uint64_t> >{}));
Кроме того, вы можете рассмотреть возможность использованияstd::integral_constant
в качестве типа возврата.Это может пригодиться, если вы хотите передать размер в другую функцию и использовать его в качестве значения constexpr
.Обратите внимание, что std::integral_constant
s неявно конвертируются в их ::type
.Неявное преобразование является одной из причин, по которой Boost.Hana
вводит свой собственный тип "целочисленная константа".Некоторые интересные примеры можно найти в главе Boost.Hana
о числах времени компиляции .В любом случае, вот простой пример с неявно конвертируемым std::integral_constant
:
#include <cstddef>
#include <tuple>
#include <type_traits>
template<class... Ts>
constexpr auto better_size_of_tuple(Type< std::tuple<Ts...> >) {
constexpr std::size_t ret = (0 + ... + sizeof(Ts));
return std::integral_constant<std::size_t, ret>{};
}