当前位置: 首页 > 知识库问答 >
问题:

结构绑定取代std::领带滥用

乐正晟
2023-03-14

在阅读这篇关于c 17最终特性的总结时,我对结构化绑定(我的重点)一节感到有点惊讶:

结构化绑定

到目前为止,有一个已知的技巧是滥用std::tie,直接将元组或对分配给不同的变量,而不必手动处理结果类型。这是一个黑客攻击,而且变量必须存在,现在你可以在一行中声明变量并初始化它们:

[a, b, c]=getvalue();

如果需要大括号,getvalues将返回一个元组。提案中没有提到std::pair,因此尚不清楚这是否适用于pair,在某些插入方法中,它是由STL返回的。

我假设他们指的是std::tie

int a,b,c;
std::tie(a,b,c) = std::make_tuple(1,2,3);

我认为这是一种推荐的做法。

有人能解释一下为什么他们把上面的例子称为黑客吗?

共有3个答案

朱博实
2023-03-14

std::tie本身具有另一个功能

它旨在创建一个引用变量的元组

创建对其参数或std::ignore实例的左值引用元组。

这对于创建动态元组很有用,而不必复制变量,因为它们是引用。我只是举了一个cppresiveusecase的例子。

bool operator<(const S& rhs) const
{
    // compares n to rhs.n,
    // then s to rhs.s,
    // then d to rhs.d
    return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
}

这里创建了元组,但它们不复制变量,而是具有引用。

现在因为他们持有参考资料,你可以“破解”它来做这样的事情

int a,b,c;
std::tie(a,b,c) = std::make_tuple(1,2,3);

它将返回的元组的值分配给本身包含引用的元组。

这甚至在CPPreference上也只是一个“注释”

std::tie可以用来解包std::pair,因为std::tuple有一个来自pair的转换赋值

在C17中,他们引入了“结构化绑定”来处理同时分配多个变量的场景。因此,无论是故意的还是黑客的,由于c 17,领带的这种用法应该不再必要了。

无论std::tie是打算这样使用,还是“黑客”可能是个人观点,我想介绍std::tie的人最清楚这一点。但是考虑到结构化绑定在那个例子中是如何取代std::tie的,他们想出了一个他们认为更好的解决方案。

洪黎昕
2023-03-14

一个非常明显的区别是d::忽略。看看这个例子

std::tuple<string, string> data {"Lord", "Buddha"};
auto [a, b] = data; //valid
auto [ , b] = data; //not valid as the identifier is strongly required
string y;
std::tie( std::ignore, y ) = data; //voila
漆雕奇
2023-03-14

我可以这么简单地说:

在一种函数只能返回一个变量的语言中

int a,b,c;
std::tie(a,b,c) = function_returning_multiple_values();

是一个黑客:

auto [a, b, c] = function_returning_multiple_values();

就像在假设的世界中,C只允许函数使用一个参数一样

int p1, p2, p3;
p1 = ...;
p2 = ...;
p3 = ...;

function_taking_multiple_params(std::tie_params(p1, p2, p3));

会是一个黑客:

function_taking_multiple_params(p1, p2, p3)

你已经习惯了C限制,一个函数最多只能返回一个对象,但实际上它只是一个人工语言限制,就像最多接受一个参数的限制是一个人工语言限制一样。

std::tie是一种针对缺少的语言特性的库攻击。它也有一些缺点:

  • 变量需要事先声明
  • 变量类型必须明确声明
  • 低效或无法与不可默认构造的类型一起使用

结构化绑定是否就是它们可能的一切?不,但在大多数情况下,它们是我们所需要的一切。

少了什么?

  • 某些元素的显式类型:例如:
auto [a, std::string b, c] = foo();

其中,ac具有推断的类型,b是显式的“std::string”

  • 筑巢。例如:
auto [a, [b1, b2], c] = foo();

其中,从foo返回的第二个对象是一个类似于tuple的对象。

  • 返回站点的语言功能(一起绕过std::tuple
auto foo() -> [int, int]

而不是

auto foo() -> std::tuple<int, int>
  • 命名返回对象
auto foo() -> [int& key, int& value]

... 好那不是很好吗

  • 再加上准备好一个很酷的新名字——通用返回初始化:
auto minmax_element(It begin, It end) -> [It min_it, It max_it];

auto [min = *min_it, max = *max_it] = minmax_element(...);

 类似资料:
  • 简短版本: 我希望能够将结构转换为元组。至少是那种类型。在下面的代码中,convertToTuple函数不起作用,因为可变参数不能用于结构化绑定(据我所知)。关键是:自动 基本上,我需要的是一种将自定义结构的类型转换为元组的方法,元组包含结构中的所有类型。例如: 具体问题: 我想创建一个模板函数,它将一个类型或一个类型列表作为模板参数,并生成一个纹理列表,每个纹理包含一个项目。另一个函数可以对纹理

  • 我在写一个函数,需要返回多个变量,其中一个是位集。然后我遇到了一些奇怪的编译错误。 我尝试了不同的编译器,它们都会产生错误,尽管消息不同。 我试着googling了一下,似乎和公共和私有继承有关。但我认为它不应该以任何方式影响这段代码。 简化代码(C 17)如下所示: 如果我移除方括号(即移除结构化绑定并使用普通自动),它就会工作。 错误消息如下: source.cpp:在函数int main()

  • 我在这里找到了最初的*C结构化绑定方案。它提出了一种轻松绑定多个返回值的方法,即: 但现在我看到每个人都指向 现在我学习了“列表是{like,this}编写的”,出现了一种新的列表语法?为什么?这里的花括号有什么问题?

  • 我已经执行了操作员的命令 头文件: cpp文件: 这对像这样的操作很有效 文件 ,但当用作 库特 结果有: 错误:无法将'std::ostream{aka std::basic_ostream}'左值绑定到'std::basic_ostream 编辑:替换为std::ostream

  • 我试图编写一个通用的obj工厂,使用可变模板调用各种类的构造函数。代码如下: 在大多数例子中,变量arg总是这样写“Args” 错误:没有可行的转换从'__bind( 在移除“ 但我不知道为什么?

  • 假设我有一个类型为 是否可以像这样以嵌套的方式访问元素类型(即在Range for循环中使用时)