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.