我想通过std :: tie(或std :: forward_as_tuple)-see玩具代码,通过std :: tuple初始化从函数返回的多个引用.
#include <tuple>
#include <iostream>
class Foo
{
public:
Foo () : m_memberInt(5),m_anotherMemberInt(7) {}
void IncrementMembers() {++m_memberInt; ++m_anotherMemberInt;}
std::tuple<int &,int &> GetMembers() {return std::tie(m_memberInt,m_anotherMemberInt);}
private:
int m_memberInt;
int m_anotherMemberInt;
};
int main()
{
Foo foo;
// Can't have dangling references.
// int &x,&y;
// std::tie(x,y) = foo.GetMembers();
std::tuple<int &,int &> tmpTuple = foo.GetMembers();
int &x = std::get<0>(tmpTuple);
int &y = std::get<1>(tmpTuple);
std::cout << x << " " << y << std::endl;
foo.IncrementMembers();
std::cout << x << " " << y << std::endl;
return 0;
}
上面的解决方案有效,但是临时std :: tuple和多个std :: gets很烦人,如果可能的话,能够避免这种情况会非常好(比如返回非引用时).
问题是我们不能有悬空引用,所以不能事先初始化变量.是否有一些C 11 / C 14的魔法允许我初始化引用,因为我调用std :: tie?或者上面是唯一的解决方案?
解决方法
在C 17中,结构化绑定为您编写代码.
std::tuple<int &,int &> tmpTuple = foo.GetMembers(); int &x = std::get<0>(tmpTuple); int &y = std::get<1>(tmpTuple);
大致相同
auto&[x,y] = foo.GetMembers();
(我的C 17代码中可能有轻微的语法错误,我缺乏经验,但你明白了.)
您可以在C 14中使用延续传递样式和适配器执行类似的操作:
template<class Tuple>
struct continue_t {
Tuple&& tuple;
using count = std::tuple_size<std::remove_reference_t<Tuple>>;
using indexes = std::make_index_sequence<count{}>;
template<std::size_t...Is>
auto unpacker(std::index_sequence<Is...>) {
return [&](auto&& f)->decltype(auto){
using std::get; // ADL enabled
return decltype(f)(f)( get<Is>(std::forward<Tuple>(tuple))... );
};
};
template<class F>
decltype(auto) operator->*( F&& f )&& {
auto unpack = unpacker( indexes{} );
return unpack( std::forward<F>(f) );
}
};
template<class F>
continue_t<F> cps( F&& f ) {return {std::forward<F>(f)};}
哪个模数错字,给你:
cps(foo.GetMembers())
->*[&](int& x,int&y)
{
std::cout << x << " " << y << std::endl;
foo.IncrementMembers();
std::cout << x << " " << y << std::endl;
};
return 0;
这很奇怪. (注意,cps支持返回对或std :: arrays以及任何“类似tuple”的函数).
实际上没有更好的方法来处理这种结构化绑定,其中有一个原因是添加到C 17.
一个可怕的预处理程序黑客可能写得如下:
BIND_VARS( foo.GetMembers(),x,y );
但是代码量会很大,我所知道的编译器没有让你调试会产生的混乱,你会得到预处理器和C交集引起的所有奇怪的怪癖等等.