6

I am currently learning metaprograming in C++, and I'm trying to see whether an element of a tuple is a pointer. I tried this approach:

int a = 3, b = 4;
auto tup = std::make_tuple(&a, b);
std::cout << std::is_pointer<decltype(std::get<0>(tup))>::value; //prints 0

I thought this was strange, so I examined the type clang deduced (I'm using clang-10), which is

__tuple_element_t<0UL, tuple<int *, int>

And it looks like some internal type.

Why do I get this weird type and what would be the proper way to get the actual type of an element of the tuple? I have only a solution which uses an intermediate auto variable, but is hardly optimal.

2 Answers 2

10

std::is_same/std::is_same_v can be very helpful in TMP and, when looking for types being equal to other types, it's invaluable when used in conjunction with static_assert.

With the following code you can see that std::get gives you a reference to the element of the tuple (as confirmed by cppreference's page on std::get), in this case int*&, where int* is the type of the element. If you use it to initialize another variable you get a copy of it (so no more reference for elem, just int*), just like int x = r; defines x to be a copy of r regardless of r being a reference or not.

#include <type_traits>
#include <tuple>

int main() {
    int a = 3, b = 4;
    auto tup = std::make_tuple(&a, b);
    auto elem = std::get<0>(tup);
    static_assert(std::is_same_v<decltype(elem), int*>,"");
    static_assert(std::is_same_v<decltype(std::get<0>(tup)), int*&>,"");
}

As regards your attempt, the fact that the second static_assert above is passing, explains why std::is_pointer<decltype(std::get<0>(tup))>::value prints false/0: that is a reference to int*, not an int*. On the other hand, the following does print true/1:

std::cout << std::is_pointer_v<std::remove_reference_t<decltype(std::get<0>(tup))>>;

See that I've used is_pointer_v instead of is_pointer and is_same_v instead of is_same? Those with _v are helper metafunctions that give you the value member of the non-_v metafunctions. remove_reference_t works similarly with respect to remove_reference, but giving the type member.

4

As Enlico explained, the type you were getting was a reference. In addition to his answer, I'd say you can get the actual type of the element of the tuple more easily with:

std::tuple_element_t<0, decltype(tup)>
1
  • 1
    User's name is "Enlico", not "Enrico" ;-)
    – LoS
    Commented Dec 12, 2023 at 9:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.