I'm trying to get size of a std::tuple
at compile time using a constexpr function.
I write this, which I thought might be easy to use and could give a clear error hint:
template<typename... TArgs>
constexpr int get_tuple_size(const std::tuple<TArgs...>&) { return sizeof...(TArgs); }
Soon I realized I don't want to construct a std::tuple
really, so I tried this:
#include <cstdio>
#include <tuple>
template<typename... TArgs>
constexpr int get_tuple_size(std::tuple<TArgs...>&&) { return sizeof...(TArgs); }
template<typename T>
constexpr T&& make_rvalue() {
return ((T&&)*(T*)0);
}
int main() {
printf("%d\n", get_tuple_size(make_rvalue<std::tuple<int, double, float&>>()));
return 0;
}
EDIT: this code can work in Clang 7.0.1
GCC 9.2.0
VS2019
This code meets all my requirements, but is it really legal?
I mean, when I write ((T&&)*(T*)0)
in a non-constexpr function, it gave an error.
error C4854: binding dereferenced null pointer to reference has undefined behavior
By the way, is there any better solution to solve it?
I have tried this:
template<typename T>
struct is_tuple {
static constexpr bool value = false;
};
template<typename... TArgs>
struct is_tuple<std::tuple<TArgs...>> {
static constexpr bool value = true;
};
template<typename T>
constexpr bool is_tuple_v = is_tuple<T>::value;
template<typename T>
struct sizeof_tuple {
static_assert(is_tuple_v<T>, "==========>sizeof_tuple input type isn't std::tuple");
};
template<typename... TArgs>
struct sizeof_tuple<std::tuple<TArgs...>> {
static constexpr size_t value = sizeof...(TArgs);
};
template<typename T>
constexpr size_t sizeof_tuple_v = sizeof_tuple<T>::value;
But if you input an wrong type, the error hint won't point to where you referenced sizeof_tuple_v<T>
but the declaration itself.