更新:请参阅下面的完整答案。简短的回答是否定的,不是直接的。您可以使用指针创建间接引用,std::reference_wrapper
或者更一般地使用指针完成相同的效果(但没有语法糖和增加的引用安全性)。
我问是因为元组在 C++11 中是一个方便的可变参数存储单元。理论上,元组的一个元素持有对同一元组中另一个元素的引用听起来是合理的。(将“reference”替换为“pointer”,它在实践中有效。)关键是构造这样一个元组的细节。考虑以下示例:
#include <tuple>
#include <iostream>
class A
{
public:
A() : val(42) { }
int val;
};
class B
{
public:
B(A &a) : _a(a) { }
int val() { return _a.val; }
private:
A &_a;
};
int main()
{
A a;
B b(a);
std::tuple<A, B> t1(a, b);
a.val = 24;
std::cout << std::get<0>(t1).val << "\n"; // 42
std::cout << std::get<1>(t1).val() << "\n"; // 24
return 0;
}
元组中的第二个元素t1
引用自动变量a
而不是 中的第一个元素t1
。有没有办法构造一个元组,使得元组的一个元素可以持有对同一元组中另一个元素的引用?我知道您可以通过创建一个引用元组来实现此结果,如下所示:
int main()
{
A a;
B b(a);
std::tuple<A &, B &> t2 = std::tie(a, b);
a.val = 24;
std::cout << std::get<0>(t2).val << "\n"; // 24
std::cout << std::get<1>(t2).val() << "\n"; // 24
return 0;
}
但出于我的目的,这是作弊,因为 in 的第二个元素t2
最终仍然引用了一个存在于元组之外的对象。我能想到的唯一方法编译得很好,但可能包含未定义的行为[编辑以反映 Howard Hinnant 提供的更简洁的示例]:
int main()
{
std::tuple<A, B> t3( A(), B(std::get<0>(t3)) ); // undefined behavior?
std::get<0>(t3).val = 24;
std::cout << std::get<0>(t3).val << "\n";
std::cout << std::get<1>(t3).val() << "\n"; // nasal demons?
}
编辑:这是一个最小的测试程序,当使用带有 -O2 或更高版本的 g++ 4.7 编译时返回非零退出状态。这表明未定义的行为或 gcc 中的错误。
#include <tuple>
class Level1
{
public:
Level1() : _touched(false), _val(0) { }
void touch()
{
_touched = true;
}
double feel()
{
if ( _touched )
{
_touched = false;
_val = 42;
}
return _val;
}
private:
bool _touched;
double _val;
};
class Level2
{
public:
Level2(Level1 &level1) : _level1(level1) { }
double feel()
{
return _level1.feel();
}
private:
int _spaceholder1;
double _spaceholder2;
Level1 &_level1;
};
class Level3
{
public:
Level3(Level2 &level2) : _level2(level2) { }
double feel()
{
return _level2.feel();
}
private:
Level2 &_level2;
};
int main()
{
std::tuple<Level3, Level2, Level1> levels(
Level3(std::get<1>(levels)),
Level2(std::get<2>(levels)),
Level1()
);
std::get<2>(levels).touch();
return ! ( std::get<0>(levels).feel() > 0 );
}