使用`std :: move`自动返回类型推导

时间:2015-09-07 08:23:19

标签: c++ c++14

通过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';
}

4 个答案:

答案 0 :(得分:6)

您有两个不同的问题:

  1. 用于检查返回类型的工具不适合用途。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*/>的变量,并从编译器生成的错误消息中读出类型。
  2. 但这在这里是无害的; f()g()确实按值返回A

    1. auto f() { return /* stuff */; }使用auto规则,这些规则从不推断出引用类型。这实际上通常是你想要的 - 你真的不想意外地返回对已经死亡的东西的引用 - 这确实是你g()在返回引用时会做的事情!
    2. 要完成返回&#34;,请使用decltype(auto)

答案 1 :(得分:2)

请参阅cppreference上的typeid operator

  

typeid( type ) - 指代表示类型std::type_info的{​​{1}}对象。如果type是引用类型,则结果引用引用的类型。

换句话说,typeid()将丢弃/忽略任何顶级引用限定符。

为了避免这种情况,您可以将类型包装成某种内容,例如type之类的函数签名,它会为您提供void(your_type)的预期结果

实施例: http://coliru.stacked-crooked.com/a/d6af3eff8216246f

答案 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引用,这意味着查询引用所引用的对象的类型,而不是引用本身的类型。