什么时候模板参数解析为左值引用的rvalue,反之亦然?

时间:2015-12-30 15:55:09

标签: c++

当我在MSDN上看到这篇文章时,我正在阅读关于右值引用和完美转发:https://msdn.microsoft.com/en-us/library/dd293668.aspx

我的问题是关于这个例子的文章:

#include <iostream>
#include <string>
using namespace std;

template<typename T> struct S;

// The following structures specialize S by 
// lvalue reference (T&), const lvalue reference (const T&), 
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of 
// the structure and its parameter.

template<typename T> struct S<T&> {
   static void print(T& t)
   {
      cout << "print<T&>: " << t << endl;
   }
};

template<typename T> struct S<const T&> {
   static void print(const T& t)
   {
      cout << "print<const T&>: " << t << endl;
   }
};

template<typename T> struct S<T&&> {
   static void print(T&& t)
   {
      cout << "print<T&&>: " << t << endl;
   }
};

template<typename T> struct S<const T&&> {
   static void print(const T&& t)
   {
      cout << "print<const T&&>: " << t << endl;
   }
};

// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t) 
{
   S<T&&>::print(std::forward<T>(t));
}

// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }

int main()
{
   // The following call resolves to:
   // print_type_and_value<string&>(string& && t)
   // Which collapses to:
   // print_type_and_value<string&>(string& t)
   string s1("first");
   print_type_and_value(s1); 

   // The following call resolves to:
   // print_type_and_value<const string&>(const string& && t)
   // Which collapses to:
   // print_type_and_value<const string&>(const string& t)
   const string s2("second");
   print_type_and_value(s2);

   // The following call resolves to:
   // print_type_and_value<string&&>(string&& t)
   print_type_and_value(string("third"));

   // The following call resolves to:
   // print_type_and_value<const string&&>(const string&& t)
   print_type_and_value(fourth());

}

我的问题是,为什么要这样说:

print_type_and_value(s1);

决心:

print_type_and_value<string&>(string& &&t)

如果我的理解是正确的,字符串&amp; &安培;&安培;是左值引用的右值引用。为什么是这样?变量s1是一个左值(它不是临时的,它是可寻址的,它可以从程序的多个部分访问),所以不应该将调用解析为字符串&amp; (一个简单的左值参考)?我不知道双重参考来自哪里。 s1是一个值,而不是一个参考,不是吗?为什么这个调用涉及rvalues?

更笼统地说,我对模板参数何时解析为T&amp; S感到困惑。 &安培;&安培; (右值参考的右值参考?)或T&amp;&amp; &安培; (对右值参考的左值引用?)。

那么,有人可以解释以下内容:

  1. 为什么对print_type_and_value(s1)的调用解析为print_type_and_value(字符串&amp;&amp;&amp; t)?
  2. 一般来说,f(var)何时解析为f(T&amp;&amp; x)或f(T&amp;&amp; x)?
  3. 我已经看过模板参数解析为T&amp;&amp ;; &amp;&amp;,它看起来像是对右值参考的右值引用。这是什么时候发生的?
  4. 当然,我知道参考崩溃规则,我理解T&amp; &安培;已经崩溃到T&amp;,但我想知道为什么这个例子中的电话解决了T&amp; &安培;&安培;首先。

    提前感谢您的帮助!

    编辑:

    我理解参考折叠的基础知识,但我想知道的一件事就是为什么这个具体的例子表现得如此。

    为什么print_type_and_value(s1)解析为print_type_and_value(字符串&amp;&amp;&amp; t),然后折叠为print_type_and_value(字符串&amp; t)?

    编辑2:

    非常感谢您的链接!我开始理解它了。

    我还有一个问题。为什么模板类型评估为字符串&amp;什么时候传递string类型的变量?

    编辑3:

    我已经重新阅读了您发布的链接,我现在100%得到它。再次感谢!

1 个答案:

答案 0 :(得分:1)

参考折叠规则使print_type_and_value<string&>(string& &&t)等同于print_type_and_value<string&>(string& t):没有参考参考。

这是excellent question/answer on SO regarding this rule