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

auto return type deduction with `std::move`

本文关键字:返回类型 std 使用 move      更新时间:2023-10-16

下面程序的输出都是1A,经过c++filt -t后都是A。我可以看到,当使用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';
}

你有两个独立的问题:

  1. 您用来检查返回类型的工具不适合使用。typeid条带参考然后顶级cv-资格;typeid(int), typeid(const int)typeid(const int&&)是一样的。要测试实际类型,请使用std::is_same;提振。TypeIndex有type_id_with_cvr。在执行template<class T> class TD;时,还有一个技巧,尝试定义TD</*type to be checked*/>类型的变量,并从编译器生成的错误消息中读出类型。

但是这里是无害的;f()g()确实返回A的值:

  • auto f() { return /* stuff */; }使用auto规则,它从不推导引用类型。这实际上通常是您想要的-您真的不想意外地返回对已经死亡的东西的引用-这确实是您的g()在返回引用时会做的事情!
  • 要得到"perfect return ",使用decltype(auto) .

    参见typeid operator on cppreference:

    typeid( type ) -表示类型为typestd::type_info对象。如果type是引用类型,则结果指向被引用的类型。

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

    为了避免这种情况,您可以将类型包装在某些东西中,例如像void(your_type)这样的函数签名,它会给出A&&

    的预期结果

    的例子:http://coliru.stacked-crooked.com/a/d6af3eff8216246f

    我可以看到,当使用std::move返回时,返回类型被推断为值类型而不是右值引用类型。对于大多数用std::move返回的用例来说是有意义的,但是这样做的原因是什么?Std::move返回一个右值引用,但是为什么返回类型自动推断为值类型?

    普通auto类型推导与普通模板参数推导相同(std::initializer_list除外)。换句话说,除非使用了通用引用&&,否则auto永远不会推导出引用。

    另一方面,

    decltype(auto)执行与auto相似的类型演绎,但还增加了额外的decltype演绎规则,允许演绎l值和r值引用。如果您希望将其作为引用推导出来,那么您可能会喜欢将其用于返回类型。

    typeid(expression)查询expressionstatic类型信息。对于任何引用,包括std::move()返回的右值引用,这意味着查询引用引用的对象的类型,而不是引用本身的类型。