std::move 在 C++ 中 T* 类型的意外行为

Unexpected behaviour of std::move on T* type in C++

我在下面的代码片段中声明了一个名为 pval 的变量,它试图在 T* 上导出 T&& [ 其中 Tint ].根据类型信息 [使用 abi 解码],派生的类型是 int*

但是当我将 int* 类型与 decltype(pval) 进行比较时,它 returns 为零而不是 1,这意味着它将 pval 视为不同于 int* 的不同类型].那么 typeidis_same 报告的 pvalint* 是错误的,这表明比较是错误的。

#include<iostream>
#include<string>
#include<typeinfo>
#include<cxxabi.h>
#include<type_traits>

using namespace std;

std::string classname(const std::type_info& info)
{
    int status;
    char* rslt=abi::__cxa_demangle(info.name(),0,0,&status);
    std::string result(rslt);
    free(rslt);
    return result;
}

int main(int argc, char* argv[])
{
    int* ptr = new int(10);
    decltype(std::move(ptr)) pval = std::move(ptr);
    cout << classname(typeid(pval)) << endl;             // as per typeid information the type of pval is int*.

    bool isSame = is_same<decltype(pval), int*>::value;  // What then is the pval not same as int* as per is_same ? 
    cout << "isSame status = " << isSame << endl;
    cout << is_same<int*, int*>::value << endl;
    return(0);
}

__cxa_demangle() 函数不会为您提供有关 const 和引用限定符的可靠(或任何?)信息。试试这个而不是你的 classname() 函数:

template <typename T, bool WithCVCorrections = true>
std::string type_name()
{
    typedef typename std::remove_reference<T>::type TR;

    std::unique_ptr<char, void(*)(void*)> own(
    abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr),
        std::free
    );
    std::string r = (own != nullptr) ? own.get() : typeid(TR).name();
    if (WithCVCorrections) {
        if (std::is_const<TR>::value)
            r += " const";
        if (std::is_volatile<TR>::value)
            r += " volatile";
        if (std::is_lvalue_reference<T>::value)
            r += "&";
        else if (std::is_rvalue_reference<T>::value)
            r += "&&";
    }
    return r;
}

... 这是基于 Howard Hinnant 的代码 here。明显的警告:这仅适用于某些编译器(不适用于 MSVC)。

decltypetypeid 的行为不同。

pval 的确切类型是 int* &&,即 int* 的右值引用。 (这就是为什么 std::is_same returns falseint* 的类型进行比较时的原因。)根据 decltype,

的行为

if the value category of expression is xvalue, then decltype yields T&&;

std::move(ptr) returns 是 xvalue

The following expressions are xvalue expressions:

  • a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as std::move(x);

然后给定 decltype(std::move(ptr)) pvalpval 的类型将是 int* &&

另一方面,typeid 的行为不同。

Refers to a std::type_info object representing the type type. If type is a reference type, the result refers to a std::type_info object representing the referenced type.

这意味着 typeid(pval) 返回的 std::type_info 对象将引用引用的类型,即 int*,而不是 int* &&


顺便说一句:什么 std::type_info::name returns 是实现定义的。