标签: structured-bindings

结构化绑定:当某些内容看起来像引用并且行为类似于引用时,但它不是引用

昨天我在SO上看到了一个关于结构化绑定的有趣问题.
我们可以总结如下.请考虑以下示例代码:

#include <tuple>
#include <type_traits>

int main() {
    auto tup = std::make_tuple(1, 2);
    auto & [ a, b ] = tup;
    // the following line won't compile for a isn't a reference
    // static_assert(std::is_reference_v<decltype(a)>);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下decltype(a)int(可能),因为这种子弹(工作草案):

if e是一个未加括号的id-expression,用于命名结构化绑定[...],decltype(e)是结构化绑定声明规范中给出的引用类型

是@Curious在评论中为感兴趣的人提供的wandbox片段.它表明实际上a不是参考,仅此而已.
到目前为止好于原来的问题,OP问为什么它int,而不是int &标准说,看上去像一个可以接受的答案.

无论如何,我想知道委员会为何如此决定.在一天结束时,a引用元组中的元素,我可以通过修改该元素a.换句话说,声明a看起来像一个引用,它的行为类似于引用,但它不是引用.

我可以忍受这个,但我想知道背后的原因是什么.为什么decltype(a)不能简单int &?亵渎者可以理解是否有一个有意义的理由?

c++ language-lawyer c++17 structured-bindings

20
推荐指数
1
解决办法
1018
查看次数

结构化绑定的用例是什么?

C++ 17标准引入了一种新的结构化绑定功能,该功能最初于2015年提出,其语法外观在后面被广泛讨论.

一看完文档就会想到它们的一些用途.

聚合分解

让我们宣布一个元组:

std::tuple<int, std::string> t(42, "foo");
Run Code Online (Sandbox Code Playgroud)

命名元素副本可以通过一行中的结构化绑定轻松获得:

auto [i, s] = t;
Run Code Online (Sandbox Code Playgroud)

这相当于:

auto i = std::get<0>(t);
auto s = std::get<1>(t);
Run Code Online (Sandbox Code Playgroud)

要么

int i;
std::string s;
std::tie(i, s) = t;
Run Code Online (Sandbox Code Playgroud)

也可以无痛地获得对元组元素的引用:

auto& [ir, sr] = t;
const auto& [icr, scr] = t;
Run Code Online (Sandbox Code Playgroud)

所以我们可以使用所有成员都是公共的数组或结构/类.

多个返回值

从上面可以直接获得从函数中获取多个返回值的便捷方法.

还有什么?

你能为结构化绑定提供一些其他的,可能不太明显的用例吗?他们还能如何提高C++代码的可读性甚至性能?

笔记

正如评论中提到的,结构化绑定的当前实现缺少一些功能.它们是非可变参数,并且它们的语法不允许显式跳过聚合成员.在这里可以找到关于可变性的讨论.

c++ c++17 structured-bindings

19
推荐指数
2
解决办法
5001
查看次数

使用结构化绑定标记为const的变量不是const

我一直在编写一组类来允许一个简单的类似python的zip函数.以下代码片段(几乎)可以正常工作.然而,这两个变量ab没有const.

std::vector<double> v1{0.0, 1.1, 2.2, 3.3};
std::vector<int> v2{0, 1, 2};

for (auto const& [a, b] : zip(v1, v2))
{
    std::cout << a << '\t' << b << std::endl;
    a = 3; // I expected this to give a compiler error, but it does not
    std::cout << a << '\t' << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我一直在使用gcc 7.3.0.这是MCVE:

#include <iostream>
#include <tuple>
#include <vector>

template <class ... Ts>
class zip_iterator
{
    using value_iterator_type = …
Run Code Online (Sandbox Code Playgroud)

c++ const c++17 structured-bindings

19
推荐指数
1
解决办法
939
查看次数

与std :: minmax和rvalues的结构化绑定

当使用std::minmax结构化绑定时,我遇到了一个相当微妙的错误.似乎传递的rvalues并不总是像人们期望的那样被复制.最初我T operator[]() const在自定义容器上使用a ,但它似乎与文字整数相同.

#include <algorithm>
#include <cstdio>
#include <tuple>

int main()
{
    auto [amin, amax] = std::minmax(3, 6);
    printf("%d,%d\n", amin, amax); // undefined,undefined

    int bmin, bmax;
    std::tie(bmin, bmax) = std::minmax(3, 6);
    printf("%d,%d\n", bmin, bmax); // 3,6
}
Run Code Online (Sandbox Code Playgroud)

使用GCC 8.1.1 -O1 -Wuninitialized将导致0,0打印为第一行,并且:

warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
Run Code Online (Sandbox Code Playgroud)

Clang 6.0.1 at -O2也会在没有警告的情况下给出错误的第一个结果.

-O0GCC给出正确的结果而没有警告.对于clang,结果似乎是正确的-O1-O0.

在rvalue仍然有效被复制的意义上,第一行和第二行不应该是等价的吗?

另外,为什么这取决于优化级别?特别是我对GCC没有发出任何警告感到惊讶.

c++ rvalue c++17 structured-bindings

19
推荐指数
2
解决办法
725
查看次数

为什么"const auto [x,y]"在绑定到引用类型时不能按预期运行?

以下代码段摘自cppref:

std::tuple<int, int&> f();

auto [x, y] = f(); 
// decltype(x) is int
// decltype(y) is int&

const auto [z, w] = f();
// decltype(z) is const int
// decltype(w) is int&
Run Code Online (Sandbox Code Playgroud)

我的问题是在最后一行:

为什么 decltype(w) int& 不是 const int&

c++ standards decltype c++17 structured-bindings

18
推荐指数
2
解决办法
408
查看次数

为什么结构化绑定会禁用RVO并在return语句上移动?

假设我们有一个名为AAA支持复制/移动的类:

class AAA
{
public:
    AAA() = default;
    ~AAA() = default;

    AAA(const AAA& rhs)
    {
       std::cout << "Copy constructor" << std::endl;
    }

    AAA(AAA&& rhs)
    {
       std::cout << "Move constructor" << std::endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

在以下代码中,get_val返回second:

AAA get_val()
{
    auto [ first, second ]  = std::make_tuple(AAA{}, AAA{});

    std::cout << "Returning - " << std::endl;
    return second;
}

auto obj = get_val();
std::cout << "Returned - " << std::endl;
Run Code Online (Sandbox Code Playgroud)

现在second被复制,打印以下输出:

...
Returning - …
Run Code Online (Sandbox Code Playgroud)

c++ rvo c++11 c++17 structured-bindings

17
推荐指数
1
解决办法
933
查看次数

复制省略是否适用于结构化绑定

强制复制省略是否适用于通过结构化绑定进行分解?以下哪种情况适用于?

// one
auto [one, two] = std::array<SomeClass>{SomeClass{1}, SomeClass{2}};

// two
auto [one, two] = std::make_tuple(SomeClass{1}, SomeClass{2});

// three
struct Something { SomeClass one, two; };
auto [one, two] = Something{};    
Run Code Online (Sandbox Code Playgroud)

我怀疑只有第三种情况允许复制省略,因为前两个会被"分解"通过std::get<>std::tuple_size<>std::get<>当参数是右值返回xvalues

标准的引用也很好!

c++ rvalue copy-elision c++17 structured-bindings

16
推荐指数
1
解决办法
827
查看次数

if语句中没有编译的结构化绑定初始化程序

阅读C++ 17,现在可以在if语句中进行多次初始化:

if (int x = func(), y = func2(); x > 0 && y > 0)
{
}
Run Code Online (Sandbox Code Playgroud)

不错的,也结合了C++ 17中的另一个功能,结构化绑定:

if (auto[iter, success] = set.insert("Hello"); success)
{   }
else    
{   }
Run Code Online (Sandbox Code Playgroud)

但是,在VisualStudio 2017中无法编译这两个功能.

if (auto[iter, success] = set.insert("Hello"), [iter2, success2] = set.insert("Foo"); success && success2)
{}
else
{}
Run Code Online (Sandbox Code Playgroud)

失踪 ';' 之前','

这是VS2017中的错误还是不可能?

c++ c++17 structured-bindings

16
推荐指数
1
解决办法
700
查看次数

为什么ADL无法使用std :: get解析为正确的函数

我正在尝试编写一个模板函数,该函数使用已解析的ADL get来获取struct/range(tuple-esque)的成员.

#include <iostream>
#include <utility>
#include <tuple>

int main() {
    auto tup = std::make_tuple(1, 2);
    std::cout << get<0>(tup) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我这样做是因为结构化绑定提案(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf§11.5.3 )说的是如何get习惯的从结构中获取元素.它表示非成员get用于从结构中获取元素.

我假设上面的代码会编译,因为ADL会导致getstd命名空间中查找函数(因为它的参数是类型std::tuple<int, int>,在其中std),在那里可以找到它.但是,我收到了一个错误.有人可以在这里解释正确的方法,以及为什么上面的代码不起作用?在这种情况下如何强制ADL发生?

c++ tuples c++17 structured-bindings

15
推荐指数
2
解决办法
461
查看次数

结构化绑定和转发引用是否组合良好?

我知道我能做到

auto&& bla = something();
Run Code Online (Sandbox Code Playgroud)

并且根据const返回值的something不同,我会得到一个不同的类型bla.

这是否也适用于结构化绑定案例,例如

auto&& [bla, blabla] = something();
Run Code Online (Sandbox Code Playgroud)

我猜是这样的(结构化绑定捎带在auto初始化器上,表现得像这样),但我找不到肯定的肯定.

更新:初步测试似乎符合我的预期(const正确推导出来):

#include <tuple>

using thing = std::tuple<char, int*, short&, const double, const float&>;

int main()
{
    char c = 0;
    int i = 1;
    short s = 2;
    double d = 3.;
    float f = 4.f;

    thing t{c, &i, s, d, f};

    auto&& [cc, ii, ss, dd, ff] = t;

    c = 10;
    *ii = 11; …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer forwarding-reference c++17 structured-bindings

15
推荐指数
1
解决办法
365
查看次数