通过1A
时,以下程序的输出全部为A
c++filt -t
。我可以看到,当使用std::move
返回时,返回类型被推导为值类型而不是右值引用类型。对于大多数使用std::move
返回的用例来说,这是有意义的,但这是什么原因? std::move
返回一个右值引用,但为什么返回类型会自动推断为值类型?
#include <iostream>
#include <memory>
#include <utility>
#include <typeinfo>
struct A
: std::unique_ptr<int>
{
auto f()
{
return A();
}
auto g()
{
return std::move(A());
}
};
int main()
{
std::cout << typeid(decltype(A().f())).name() << ' ';
std::cout << typeid(decltype(A().g())).name() << ' ';
std::cout << typeid(A).name() << '\n';
}
答案 0 :(得分:6)
您有两个不同的问题:
typeid
剥离参考,然后是顶级cv资格; typeid(int)
,typeid(const int)
和typeid(const int&&)
是一回事。要测试实际类型,请使用std::is_same
; Boost.TypeIndex有type_id_with_cvr
。您还可以执行template<class T> class TD;
,尝试定义类型TD</*type to be checked*/>
的变量,并从编译器生成的错误消息中读出类型。但这在这里是无害的; f()
和g()
确实按值返回A
:
auto f() { return /* stuff */; }
使用auto
规则,这些规则从不推断出引用类型。这实际上通常是你想要的 - 你真的不想意外地返回对已经死亡的东西的引用 - 这确实是你g()
在返回引用时会做的事情!要完成返回&#34;,请使用decltype(auto)
。
答案 1 :(得分:2)
请参阅cppreference上的typeid operator:
typeid( type )
- 指代表示类型std::type_info
的{{1}}对象。如果type
是引用类型,则结果引用引用的类型。
换句话说,typeid()将丢弃/忽略任何顶级引用限定符。
为了避免这种情况,您可以将类型包装成某种内容,例如type
之类的函数签名,它会为您提供void(your_type)
的预期结果
答案 2 :(得分:1)
我可以看到,当使用std :: move返回时,返回类型被推导为值类型而不是rvalue引用类型。对于大多数使用std :: move返回的用例来说,这是有道理的,但是这是什么原因? std :: move返回一个右值引用,但为什么返回类型会自动推导为值类型?
普通auto
类型推导与普通模板参数推导相同(std::initializer_list
除外)。换句话说,除非使用通用引用auto
,否则&&
永远不会推断引用。
decltype(auto)
对auto
执行类似的类型推导,但还添加了额外的decltype
推导规则,允许推导出l值和r值引用。如果您希望将其作为参考推断,那么您可能希望将其用于返回类型。
答案 3 :(得分:0)
typeid(expression)
查询有关expression
的静态类型的信息。对于任何引用,包括std::move()
返回的rvalue引用,这意味着查询引用所引用的对象的类型,而不是引用本身的类型。