Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Unexpected behavior with std::is_same_v

I was writing a function that checks what type a pointer was pointing to, but std::is_same_v returns false when you make the pointer const.

Here is a minimal reproducible example of what is supposed to work:

#include <type_traits>

template<typename T>
constexpr bool checkType() {
    return std::is_same_v<std::remove_pointer_t<std::remove_cv_t<std::decay_t<T>>>, char>;
}

int main() {
    static_assert(checkType<char*>(), "char* should be true");
    static_assert(checkType<const char*>(), "const char* should be true");
    return 0;
}

I’ve tried changing the order of std::remove_cv_t<std::decay_t<T>> to std::decay_t<std::remove_cv_t<T>> or even getting rid of std::decay_t altogether, but it still does not work. I’ve also tried checking the type returned by std::remove_pointer_t with this code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include <type_traits>
#include <iostream>

template<typename T>
void do_() {
#define cx std::remove_pointer_t<std::remove_cv_t<std::decay_t<T>>>
    std::cout <<
    "T: " << typeid(T).name() << " (" << typeid(T).raw_name() << "), " <<
    "Tred: " << typeid(cx).name() << " (" << typeid(cx).raw_name() << "), \n" <<
    "icb?: " << (std::is_same_v<cx, char> ? "true" : "false") << ", " <<
    "iib?: " << (std::is_same_v<cx, int> ? "true" : "false")
    << "\n";
}

int main() {
    do_<char>();
    do_<char*>();
    do_<const char*>();
    do_<int>();
    do_<int*>();
    do_<const int*>();
    return 0;
}

which returns the following:

T: char (.D), Tred: char (.D),
icb?: true, iib?: false
T: char * __ptr64 (.PEAD), Tred: char (.D),
icb?: true, iib?: false
T: char const * __ptr64 (.PEBD), Tred: char (.D),
icb?: false, iib?: false
T: int (.H), Tred: int (.H),
icb?: false, iib?: true
T: int * __ptr64 (.PEAH), Tred: int (.H),
icb?: false, iib?: true
T: int const * __ptr64 (.PEBH), Tred: int (.H),
icb?: false, iib?: false

which doesnt make any sense to me since the name of the types are the same… but arent the same type?
I’m using Clang 17.0.4 (C++23), but I’ve also tested this in MSVC (C++20) and the same behavior occurs.

>Solution :

If your goal is to check whether T is a pointer to char (or const char), you need to adjust your type traits usage. You want to remove the pointer but not the const qualifier before comparing with char.

Here’s a revised version of your checkType function that should work for both char* and const char*:

#include <type_traits>

template<typename T>
constexpr bool checkType() {
    using DecayedType = std::remove_pointer_t<T>; // Only remove pointer, keep const if present
    return std::is_same_v<DecayedType, char> || std::is_same_v<DecayedType, const char>;
}

int main() {
    static_assert(checkType<char*>(), "char* should be true");
    static_assert(checkType<const char*>(), "const char* should be true");
    return 0;
}

This revised version correctly handles both char* and const char* by comparing the decayed type (without the pointer) against both char and const char.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading