I was trying to static_assert
that some meta transformer algorithm worked, and it incredibly did not compare to same, even though the typeid().name()
returned the exact same string.
A repetition of the type expression in the typedef could fix the is_same
, but I can't understand how repeating the initializer expression in the typedef changes the type, over taking the decltype of an auto variable initialized with that same expression.
A more concrete explanation of what I was doing:
I did a meta transformer that can transform a meta value list (containing enumerators) to a std::tuple of all enumerators. Then I checked that the tuple generated was the one I expected.
all code hereunder, check the line with the comments // works // doesn't work
And the final test is at the end.
#include <type_traits>
#include <tuple>
template<typename T> struct ValueListAsTuple; // master template
// destructurer of list:
template<template <auto...> class L, auto... Vs>
struct ValueListAsTuple<L<Vs...>>
{
static constexpr auto value = std::make_tuple(Vs...);
//using type = decltype(std::make_tuple(Vs...)); // works
using type = decltype(value); // doesn't work
};
// template typedef
template<typename T> using ValueListAsTuple_t = typename ValueListAsTuple<T>::type;
struct Kind
{
enum EnumType { E1, E2 };
template <auto... Values> struct MetaVals{}; // meta value list
using MetaValueList = MetaVals<
E1,
E2
>;
};
int main(int argc, const char* argv[])
{
auto tuple = ValueListAsTuple_t< Kind::MetaValueList > {};
//std::cout << typeid(tuple).name() << '\n';
// this prints: "class std::tuple<enum Kind::EnumType, enum Kind::EnumType>"
// manual re-creation of the type, for testing:
std::tuple< Kind::EnumType, Kind::EnumType > t2;
//std::cout << typeid(t2).name() << '\n';
// this prints the exact same thing.
static_assert( std::is_same_v< std::tuple_element<0, decltype(tuple)>::type, Kind::EnumType > );
static_assert( std::is_same_v< std::tuple_element<1, decltype(tuple)>::type, Kind::EnumType > );
// WHAT ???
static_assert( std::is_same_v<
ValueListAsTuple_t< Kind::MetaValueList >,
std::tuple< Kind::EnumType, Kind::EnumType >
> );
// is_convertible_v works but I don't care ! wth ?
}
So as you can see, is_same
could not deduce the same type when the type
was declared through value
but it worked if I repeat std::make_tuple(..
. I can't see where there is any difference between the 2 forms.
I even checked element by element that the types are the same at each index of the tuple.
Check that in action in godbolt:
https://godbolt.org/z/QUCXMB
The behavior is the same across gcc/clang/msvc
It's a trivial error, really, but hard to spot unfortunately. The issue you face is because constexpr
implies const
. So in your example type
is const tuple<...>
, which is not the same type as the non cv-qualified type you check. A short fix to the alias should make your test pass:
using type = std::remove_const_t<decltype(value)>;