不知何故,受到 Paul Preney 编写的Expression templates 和 C++11中的表达式模板代码的启发,我决定测试以下内容:
template<typename T>
struct X
{
X(T t) : t(std::forward<T>(t)) {}
T t;
};
template<typename T>
auto CreateX(T&& t) -> X<decltype(std::forward<T>(t))>
{
return X<decltype(std::forward<T>(t))>(std::forward<T>(t));
}
然后,我用它来生成 and 的一个实例,X<const vector<int>&>
如下X<vector<int>&&>
所示:
int main()
{
int vec = {1,2,3,4};
auto x1 = CreateX(vec);
auto x2 = CreateX(vector<int>{5,6,7,8});
cout << "x1: "; for(auto x : x1.t) cout << x << " "; cout << endl;
cout << "x2: "; for(auto x : x2.t) cout << x << " "; cout << endl;
}
输出是:
x1: 1 2 3 4
x2: 0 0 33 0 0 0 7 8
这表明临时的生命周期vector<int>{5,6,7,8}
没有被延长,并且右值引用成员X::t
绑定到其他东西。
好的,从这个答案const 引用右值的类数据成员的生命周期是多少?,我知道这是预期的行为。
但是,这里的问题是:只要右值引用成员存在,Paul Preney 的表达式模板和 C++11中的代码有什么不同,它允许临时向量存在?请参阅他的案例 2,其中创建了临时对象。
显然,这里使用了相同的构造,但我可能遗漏了一些东西。
编辑: 根据下面 R. Martinho Fernandes 的回答,我尝试了以下方法:
int main()
{
using namespace std;
auto expr = math_vector<3>{1.0, 1.1, 1.2} + math_vector<3>{2.0, 2.1, 2.2};
cout << "vec1: "; for(int i = 0; i < 3; ++i) cout << expr.le()[i] << " "; cout << endl;
cout << "vec2: "; for(int i = 0; i < 3; ++i) cout << expr.re()[i] << " "; cout << endl;
}
事实证明这是输出的有效代码:
vec1: 1.0 1.1 1.2
vec2: 2.0 2.1 2.2
因此,显然存储在表达式模板中的引用不是悬空的。这里发生了什么?