std::is_same_v 的意外行为

Unexpected behavior with std::is_same_v

提问人:edc 提问时间:11/11/2023 更新时间:11/11/2023 访问量:69

问:

我正在编写一个函数来检查指针指向的类型,但是当您使指针 const 时,std::is_same_v 返回 false。

下面是一个最小的可重现的例子,说明应该做什么:

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

我试过更改 to 的顺序,甚至完全摆脱,但它仍然不起作用。我还尝试使用以下代码检查返回的类型:std::remove_cv_t<std::decay_t<T>>std::decay_t<std::remove_cv_t<T>>std::decay_tstd::remove_pointer_t

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

它返回以下内容:

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

这对我来说没有任何意义,因为类型的名称是相同的......但不是同一种类型吗? 我正在使用 Clang 17.0.4 (C++23),但我也在 MSVC (C++20) 中对其进行了测试,并且发生了相同的行为。

C++ 模板

评论

3赞 HolyBlackCat 11/11/2023
const char*是“指向 const char 的(non-con-st) 指针”。 对它没有影响,因为它不是常量,也不是引用。 没有效果,因为它不是常量。 将其转换为“const char”。decay_tremove_cv_tremove_pointer_t
0赞 edc 11/11/2023
为什么 typeid(cx).raw_name() 会返回与 char 或 int 相同的原始名称呢?
0赞 HolyBlackCat 11/11/2023
typeid忽略顶级的一致性和参考性。这里有一种没有的方法:stackoverflow.com/a/59522794/2752075

答:

4赞 Ninja 11/11/2023 #1

如果你的目标是检查 T 是否是指向 char(或 const char)的指针,则需要调整类型特征的使用。在与 char 进行比较之前,您希望删除指针而不是 const 限定符。

下面是 checkType 函数的修订版本,它应该适用于 char* 和 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;
}

此修订版本通过将衰减类型(不带指针)与 char 和 const char 进行比较,正确地处理了 char* 和 const char*。

评论

1赞 Ted Lyngmo 11/11/2023
虽然意志有效,但在比较之前删除会使意图更清晰(i.m.o.):||constreturn std::is_same_v<std::remove_const_t<DecayedType>, char>;