炸鱼薯条德里克
炸鱼薯条德里克

Reputation: 999

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?

Upvotes: 15

Views: 2490

Answers (3)

songyuanyao
songyuanyao

Reputation: 172924

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 {};

Upvotes: 13

Andr&#233; Bergner
Andr&#233; Bergner

Reputation: 1439

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>> {}

Upvotes: 9

Jarod42
Jarod42

Reputation: 217255

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

So you have to handle cv qualifier somewhere.

Upvotes: 16

Related Questions