我想知道为什么要做出这个选择.它将允许以非常清晰和整洁的方式编写许多函数..例如:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = { b, a };
while (b > 0)
std::tie(a, b) = { b, a % b };
return a;
}
Run Code Online (Sandbox Code Playgroud)
std::initializer_list是一个同类的项目集合,std::tuple而是异构的.唯一有意义定义std::tuple::operator=for的情况std::initializer_list是元组是同构的并且与初始化列表具有相同的大小,这种情况很少发生.
解决方案/解决方法:您可以使用std::make_tuple:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::make_tuple(b, a);
while (b > 0)
std::tie(a, b) = std::make_tuple(b, a % b);
return a;
}
Run Code Online (Sandbox Code Playgroud)
...或者std::tupleC++ 17中的构造函数(感谢类模板的模板参数推导):
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::tuple{b, a};
while (b > 0)
std::tie(a, b) = std::tuple{b, a % b};
return a;
}
Run Code Online (Sandbox Code Playgroud)
为什么
std::tie(a,b) = {b, a};
Run Code Online (Sandbox Code Playgroud)
不编译?
{}赋值右侧只能调用 参数的非显式构造函数operator=。
可用的重载operator=有:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
template< class... UTypes >
tuple& operator=( const tuple<UTypes...>& other );
template< class... UTypes >
tuple& operator=( tuple<UTypes...>&& other );
template< class U1, class U2 >
tuple& operator=( const pair<U1,U2>& p );
template< class U1, class U2 >
tuple& operator=( pair<U1,U2>&& p );
Run Code Online (Sandbox Code Playgroud)
运算template符重载无法从中推断出它们的类型{}(注意:这在 C++17 中可能会改变),留下:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
Run Code Online (Sandbox Code Playgroud)
tuple在这种情况下在哪里std::tuple<int&, int&>。
完美的前向逐元素构造的元组构造函数tuple<Ts...>是显式的(该列表中的#3)。 {}不会调用显式构造函数。
有条件的非显式构造函数采用Ts const&...; Ts如果不可复制,则它不存在,并且int&不可复制。
因此,没有可用的类型可以构造{int&, int&},并且重载解析失败。
为什么标准没有解决这个问题?好吧,我们可以自己做!
为了解决这个问题,我们必须添加一个特殊的(Ts...)非显式构造函数,tuple该构造函数仅在Ts类型均为引用时才存在。
如果我们写一个玩具元组:
struct toy {
std::tuple<int&, int&> data;
toy( int& a, int& b ):data(a,b) {} // note, non-explicit!
};
toy toy_tie( int& a, int& b ) { return {a,b}; }
Run Code Online (Sandbox Code Playgroud)
并使用它,你会注意到
std::tie(a, b) = {b, a};
Run Code Online (Sandbox Code Playgroud)
编译并运行。
然而,
std::tie(a, b) = { b, a % b };
Run Code Online (Sandbox Code Playgroud)
不,因为a%b不能绑定到int&。
然后我们可以增加toy:
template<class...>
toy& operator=( std::tuple<int, int> o ) {
data = o;
return *this;
}
Run Code Online (Sandbox Code Playgroud)
(+默认的特殊成员函数。 template<class...>确保它的优先级低于特殊成员函数,因为它应该)。
这让 allocate-from {int,int}。然后我们运行它并......得到错误的结果。的 gcd5,20为20. 什么地方出了错?
toy_tie(a, b) = std::tie( b, a );
Run Code Online (Sandbox Code Playgroud)
同时使用a和b绑定到引用不是安全的代码,这就是
toy_tie(a, b) = { b, a };
Run Code Online (Sandbox Code Playgroud)
做。
简而言之,正确地做到这一点是很棘手的。在这种情况下,为了安全起见,您需要在分配之前获取右侧的副本。知道何时复制、何时不复制也很棘手。
隐式地进行这项工作看起来很容易出错。因此,从某种意义上说,它不起作用是偶然的,但修复它(虽然可能)看起来是一个坏主意。
| 归档时间: |
|
| 查看次数: |
403 次 |
| 最近记录: |