我见过this question。 似乎无论演员如何,临时对象都将“存活”直到评估完全表达。 但在以下场景中:
template<class T>
struct bar {
T t;
bar(T t) : t(t) {}
template<class U>
bar(bar<U> other) : t(other.t) {}
};
void foo(bar<const double&> b) {
printf("%lf\n", b.t);
}
int main() {
foo(bar<const double&>(2));//#1
foo(bar<int>(2)); //#2
return 0;
}
1运行良好,但2运行不顺利。 并且MSVC给了我一个关于2的警告:“引用成员被初始化为一个临时的,在构造函数退出后不会持久”
现在我想知道他们为什么要制作一个临时的double
对象并将其传递给bar<const double&>
而只有2个失败。
@Update
我在原帖中使用struct bar而不是boost::tuple
,希望对其他人更熟悉。
让我更清楚地提出我的问题。在#1中,从double
(2)创建时间int
,然后从中创建bar<const double &>
并将其复制到foo
中,而在#2中创建时间bar<int>
已创建double
,并在bar<int>
的{{1}}的{{1}}成员中创建时间bar<const double&>
。似乎时间double
在#2中的foo
中被破坏而在#1中没有被破坏。为什么?我认为它们都是完整性的一部分,并且在bar
返回之前一直存在。
int i = 2;
并将i
传递给了两个电话,但事情就像以前一样。我是在VS2008中使用调试模式制作的。
答案 0 :(得分:1)
在#2中,时间tuple<double const&>
由tuple<int>
构成
作为n
的参数foo
。
在tuple<double const&>
构造之前,时间双(D)是
从tuple<int>
的int成员和double const&
构造
成员初始化为D.
构造用于准备函数参数的时间对象被破坏
当函数调用完成时。
因此,当tuple<double const&>
的构造函数完成时,D被破坏。
希望这有帮助
答案 1 :(得分:1)
。#1调用boost::tuple<const double&>::tuple(const double&)
。为此,临时double
由完整表达式foo(boost::tuple<const double&>(2))
创建。然后创建临时boost::tuple<const double&>
。它有一个绑定到临时double
的引用成员。两个临时值都存在,直到完全表达#1完成,并且在调用foo
时仍然有效。
。#2拨打boost::tuple<const double&>::tuple(const boost::tuple<int>&)
。此表达式创建临时boost::tuple<int>
。临时的生命周期同样不是问题。但请考虑调用tuple
构造函数时会发生什么。简化/伪代码类:
template<> class tuple<int> {
private:
int member1_;
//...
};
template<> class tuple<const double&> {
private:
const double& member1_;
public:
tuple(const tuple<int>& int_tup) : member1_(int_tup.member1_) {}
// ...
};
mem-initializer member1(int_tup.member1_)
将int
值转换为临时double
,并将double
绑定到类引用成员。此临时double
由完整表达式member1_(int_tup.member1_)
创建,而不是由完整表达式foo(boost::make_tuple(2))
创建。 mem-initializers的一个特殊例外保证临时double
在创建它的构造函数结束之前是可以的,但是当调用foo
时,不能保证它仍然有效。
因此,重要的区别在于语句#1创建了临时double
本身,但语句#2间接导致在另一个函数中创建临时double
。完全 完整表达式创建一个临时文件会影响该临时文件的生存时间。
答案 2 :(得分:0)
我相信第1行是正确的,因为允许const引用引用临时数。有人可能会引用这个标准。
答案 3 :(得分:0)
前言:我不是Boost或Tuple专家。我也没用过。无论如何,我会尝试提供帮助。
在我看来,boost::make_tuple(2)
正在返回tuple<int>
。但是,似乎有一个隐式强制转换符合您的foo
实现,在此期间它可能会尝试不恰当地获取临时地址(将int
转换为const double&
)。
您是否尝试过明确地投射make_tuple
?
同样,我不是推特或元组专家,但我会尝试:
foo(boost::make_tuple(boost::cref((double)2)));//#2
或
foo(boost::make_tuple((const double&)2);//#2
我承认我在这里采取了有根据的猜测,试图提供帮助,所以我不保证这是正确的树。