0

我正在阅读decltypeScott Meyers 所著的有效现代 C++ 中的引用和右值引用。我有以下代码

template <typename container, typename index>
decltype(auto) authAndAccess(container&& c, index i)  {
    std::cout << "auth and Access c type: " << typeid(c[i]).name() << std::endl;
    std::cout << "auth and Access c type expecting reference: " << typeid(std::forward<container>(c)[i]).name() << std::endl;
    return std::forward<container>(c)[i];
}

deque<int> makeStringDeque() {
    deque<int> dqContainer = { 1,2,3,4,5 };
    return dqContainer;
}

现在在主要功能中我有以下

deque<int> dqContainer = { 1,2,3,4,5 };
std::cout << "Value returned by container: " << authAndAccess(dqContainer, 4) << std::endl;
authAndAccess(deque<int>{1, 2, 3, 4, 5}, 4) = 10;
std::cout << "Value returned by container and 5th element after copying: " << dqContainer[4] << endl;

我的问题是authAndAccess函数接受右值参数,所以容器是临时的,返回的是对象是临时参考元素。但是为什么输出显示为inttypeid所期望的 forwared int &。我确实理解 typeid 的 name 函数不准确,但是为什么在我们返回临时元素引用时它没有崩溃。

4

1 回答 1

2

我的问题是authAndAccess函数接受右值参数,所以容器是临时的,返回的是对象是临时参考元素。

authAndAccess接受 Scott 所说的通用引用,现在称为转发引用,因此它可以接受左值和右值参数。当你传递一个左值时,你会得到一个左值引用,当你传递一个右值时,你会得到一个右值引用。 std::forward<container>做同样的事情。如果container是左值,则获得左值,而对于右值,则获得右值。

这意味着authAndAccess(dqContainer, 4)很好,因为您正在返回对dqContainer仍然存在的对象的引用。authAndAccess(makeStringDeque(), 4)你会认为你有未定义的行为,因为它makeStringDeque()是一个临时的并且你正在返回对它的引用,但由于你不保留它,所以没有 UB,因为引用将在完整表达式结束之前有效。


但是为什么输出显示为inttypeid所期望的 forwared int &

typeid不会告诉你有没有参考。您可以在这个最小的示例中看到

int main(int argc, char* argv[])
{
    int a = 5;
    int & b = a;
    std::cout << typeid(b).name();
}

哪个输出i。如果您想获得类型,您可以使用已声明但未定义的类模板并为其提供类型,您将收到一条错误消息,告诉您实际类型是什么。如果我们把上面的代码改成

template<typename T>
struct type;

int main(int argc, char* argv[])
{
    int a = 5;
    int & b = a;
    type<decltype(b)>{};
}

我们会得到一个错误

main.cpp:14:5: error: implicit instantiation of undefined template 'type<int &>'
    type<decltype(b)>{};

如您所见,它将类型推断为int &. 如果我们在您的代码中这样做,它也会给出,int &因为这是c[i].

于 2019-04-03T13:27:58.500 回答