相关文章推荐
乖乖的蜡烛  ·  iOS ...·  5 月前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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.

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.

As Enrico 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)>
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.