Why I have strange output for this code? How to test for a type in the right way?
#include <iostream>
#include <tuple>
#include <type_traits>
template<typename T> struct is_tuple : std::false_type {};
template<typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {};
struct TraitBlock {
using BlockLocation = struct { std::uint64_t x, y, z; };
};
struct TraitRock {};
struct ItemTemplate{
static constexpr auto traits = std::make_tuple(
TraitBlock{},
TraitRock{}
);
};
int main(){
using A = std::tuple<char, int,double,char>;
std::cout << is_tuple<decltype(ItemTemplate::traits)>::value
<< is_tuple<decltype(std::make_tuple(
TraitBlock{},
TraitRock{}
))>::value
<< std::endl;
}
I use mingw64-gcc 7.2.0 with -std=c++17, I got output "01" Why I got two different output? Aren't they the same type?
Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of std::pair.
Given a tuple, you can extract the type of the N th element in the tuple with the help of std::tuple_element_t<N, Tuple> : // example = char using example = std::tuple_element_t<1, std::tuple<int, char, float>>; The index is zero-based, so element 0 is int , element 1 is char , and element 2 is float .
Tuples in C++A tuple is an object that can hold a number of elements. The elements can be of different data types. The elements of tuples are initialized as arguments in order in which they will be accessed.
Initializes each element of the tuple with the corresponding element of other . This constructor is constexpr if every operation it performs is constexpr. For the empty tuple std::tuple<>, it is constexpr.
decltype(ItemTemplate::traits)
is const std::tuple<TraitBlock, TraitRock>
.
So you have to handle cv qualifier somewhere.
Note that the type of ItemTemplate::traits
(i.e. decltype(ItemTemplate::traits)
) is const std::tuple<TraitBlock, TraitRock>
, which doesn't match the specified type (i.e. std::tuple<Ts...>
) in the specialization of is_tuple
.
You can remove the const-ness by std::remove_const, e.g.
std::cout << is_tuple<std::remove_const_t<decltype(ItemTemplate::traits)>>::value;
or add another specialization for const
(and might volatile
as well):
template<typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {};
template<typename... Ts> struct is_tuple<const std::tuple<Ts...>> : std::true_type {};
template<typename... Ts> struct is_tuple<volatile std::tuple<Ts...>> : std::true_type {};
template<typename... Ts> struct is_tuple<const volatile std::tuple<Ts...>> : std::true_type {};
You need to remove all qualifiers. Instead of doing this all yourself you should use std::decay_t
which removes all qualifiers for you and dispatch to your trait. For instance
template<typename T>
struct is_tuple_impl : std::false_type {};
template<typename... Ts>
struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
template<typename T>
struct is_tuple : is_tuple_impl<std::decay_t<T>> {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With