Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect whether a type is std::tuple or not?

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?

like image 327
炸鱼薯条德里克 Avatar asked Sep 07 '17 10:09

炸鱼薯条德里克


People also ask

What is a std :: tuple?

Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of std::pair.

How do you determine the type of tuple element?

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 .

Does C++ have tuple?

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.

Is tuple a Constexpr?

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.


3 Answers

decltype(ItemTemplate::traits) is const std::tuple<TraitBlock, TraitRock>.

So you have to handle cv qualifier somewhere.

like image 122
Jarod42 Avatar answered Oct 16 '22 16:10

Jarod42


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 {};
like image 24
songyuanyao Avatar answered Oct 16 '22 15:10

songyuanyao


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>> {}
like image 9
André Bergner Avatar answered Oct 16 '22 17:10

André Bergner