【问题标题】:Unexpected behaviour of std::move on T* type in C++C++ 中 T* 类型上 std::move 的意外行为
【发布时间】:2018-11-01 10:18:37
【问题描述】:

我在下面的代码 sn-p 中声明了一个名为 pval 的变量,该变量试图在 T* [与 Tint ] 上派生 T&&。根据类型信息 [使用 abi 解码],派生的类型是 int*

但是当我将int* 类型与decltype(pval) 进行比较时,它返回零而不是1,这意味着它将pval 视为与int* 不同的类型。那么typeidis_same 报告的int* 是错误的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);
}

【问题讨论】:

  • 抱歉错过了,以后会继续的
  • 谢谢burnabyRails :),我现在已经用对我有帮助的正确/最准确的答案标记了我所有的问题。
  • 很高兴看到你有。您已经获得了一些代表和学者徽章!以防万一,没有必要过度。接受的答案应该基本上可以解决您的问题。无论如何,这是你的电话。我很快就会在这里删除我所有的 cmets。
  • 是的,大部分答案都解决了我的问题。是的,我得到了更多的积分和声望谢谢!!享受我的帽子..... :)

标签: c++ c++11 decltype typeid value-categories


【解决方案1】:

decltypetypeid 的行为不同。

pval 的确切类型是int* &amp;&amp;,即对int* 的右值引用。 (这就是std::is_sameint*的类型比较时返回false的原因。)根据decltype的行为,

如果表达式的值类别是xvalue,则decltype产生T&&;

std::move(ptr) 返回的是xvalue

以下表达式是 xvalue 表达式:

  • 函数调用或重载的运算符表达式,其返回类型为对对象的右值引用,例如std::move(x)

那么给定decltype(std::move(ptr)) pvalpval 的类型将是int* &amp;&amp;

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

引用代表type 类型的std::type_info 对象。如果type 是引用类型,则结果引用代表被引用类型的std::type_info 对象。

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


顺便说一句:std::type_info::name 返回的是实现定义的。

【讨论】:

  • 了解我的类名函数本身并不准确,如下所示,这使事情更加清晰明确。谢谢你。
【解决方案2】:

__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)。

【讨论】:

  • 像魔术一样工作,感谢 einpoklum 的帮助,我今天学到了一些关于 typeid 未涵盖的内容:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-17
  • 2016-03-21
  • 2021-10-01
  • 2017-05-28
  • 2018-11-27
相关资源
最近更新 更多