在阅读这篇关于c ++ 17最终特性的摘要时,我对结构化绑定(强调我的)部分感到有些惊讶:
结构化绑定
到目前为止,有一种已知的技巧滥用std :: tie直接将元组或对分配给不同的变量,而不必手动处理结果类型.这是一个hack,并且变量必须存在,现在你可以声明变量并在一行中初始化它们:
auto [a,b,c] = getvalues();
需要大括号,getvalues返回一个元组.提案中没有提到std :: pair,因此不清楚它是否适用于在某些插入方法中由STL返回的pair.
我假设他们提到了这种用法 std::tie
int a,b,c;
std::tie(a,b,c) = std::make_tuple(1,2,3);
Run Code Online (Sandbox Code Playgroud)
我认为这是一种推荐的做法.
有人可以解释为什么他们将上述例子称为黑客攻击吗?
我正在尝试为类提供类似元组的结构化绑定访问.为简单起见,我将在本文的其余部分使用以下类:
struct Test
{
int v = 42;
};
Run Code Online (Sandbox Code Playgroud)
(我知道这个类支持开箱即用的结构化绑定,但我们假设它没有.)
要启用对成员的类似元组的访问Test,我们必须专门化std::tuple_size并且std::tuple_element:
namespace std
{
template<>
struct tuple_size<Test>
{
static const std::size_t value = 1;
};
template<std::size_t I>
struct tuple_element<I, Test>
{
using type = int;
};
}
Run Code Online (Sandbox Code Playgroud)
而我们需要的最后一部分是要么Test::get<i>或函数get<i>(Test)中Test的命名空间.让我们实现后者:
template<std::size_t I>
int get(Test t)
{
return t.v;
}
Run Code Online (Sandbox Code Playgroud)
这有效.但是,我想返回对Test成员的引用std::get(std::tuple),例如,就像.因此,我实现get如下:
template<std::size_t I>
int& get(Test& t)
{
return t.v;
}
template<std::size_t I> …Run Code Online (Sandbox Code Playgroud) 我正在经历Herb Scutter的
旅程:走向更强大,更简单的C++编程
结构绑定部分
为了理解这个概念.Best是编写一个我试过的程序,但是遇到了一些错误
只是想尝试如何在类上使用私有数据的结构绑定.请忽略下面的示例.如果您能提供任何示例
#include<iostream>
#include<string>
using namespace std;
class foobar {
public:
foobar() { cout << "foobar::foobar()\n"; }
~foobar() { cout << "foobar::~foobar()\n"; }
foobar( const foobar &rhs )
{ cout << "foobar::foobar( const foobar & )\n"; }
void ival( int nval, string new_string ) { _ival = nval;s=new_string; }
private:
int _ival;
string s;
};
foobar f( int val,string new_string ) {
foobar local;
local.ival( val,new_string );
return local;
}
template<> struct tuple_element<0,foobar> { using …Run Code Online (Sandbox Code Playgroud) 我有一个模板,该模板的类型可以在结构上绑定到两个别名(可以是一个元组,也可以是一个结构)。我需要别名指向的两个变量的类型。
template <typename T>
T obj;
// type of a/b in auto&& [a, b] = obj ?
Run Code Online (Sandbox Code Playgroud)
在实际使用结构化绑定之前,我需要知道类型:
template <typename S>
void fn(ranges::any_view<S> range_of_tuple_or_struct_or_pair) {
last_from = std::numeric_limits<?????>::max();
// ????? should be the type of from (or to, they should be the same types) of:
// auto&& [from, to] = <range element>
for (auto&& [from, to] : range_of_tuple_or_struct_or_pair) {
if (from != last_from) {
...;
last_from = from;
}
}
}
Run Code Online (Sandbox Code Playgroud) 正如dcl.struct.bind中引用的那样,
让 cv 表示 decl-specifier-seq 中的 cv 限定符。
将 E 的非静态数据成员指定为 m 0 、 m 1 、 m 2 、...(按声明顺序),每个 vi 是一个左值的名称,该左值引用 e 的成员 mi ,其类型为 cv T i ,其中 T i 是该成员的声明类型;
如果我理解正确,cv 限定符是从结构化绑定的声明中传播的。
假设我有一个简单的结构,
struct Foo {
int x;
double y;
};
Run Code Online (Sandbox Code Playgroud)
考虑两种情况,
const Foo f{1, 1.0};
auto& [x, y] = f;
// static_assert(std::is_same<decltype(x), int>::value); // Fails!
static_assert(std::is_same<decltype(x), const int>::value); // Succeeds
Run Code Online (Sandbox Code Playgroud)
现场演示。的 cv-qualifier 是否x来自扣除auto?
第二个,
Foo f{1, 1.0};
const auto& [x, …Run Code Online (Sandbox Code Playgroud) 当我尝试编译以下代码时,出现错误 C2280。我猜编译器正在尝试复制 unique_ptr 或其他东西。
#include <memory>
std::pair<int, std::unique_ptr<int>> CreatePair()
{
std::unique_ptr<int> my_int(new int);
return { 1, std::move(my_int) };
}
std::unique_ptr<int> GetUinquePtr()
{
auto [ignore, unique_ptr] = CreatePair();
return unique_ptr; // <- Build error C2280 attempting to reference a deleted function
}
int main()
{
auto unique_ptr = GetUinquePtr();
}
Run Code Online (Sandbox Code Playgroud)
完整的错误消息:
error C2280: 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)
如果我添加 std::move() 它就会起作用:
std::unique_ptr<int> GetUinquePtr()
{
auto [ignore, unique_ptr] = CreatePair();
return std::move(unique_ptr); // <- This works
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 …
在发现您可以符合人体工程学地将 s 转换 std::vector为固定大小的std::spans 后,我想我应该尝试以下结构化绑定std::vector:
auto _ = std::vector{ 1,2,3 };
std::span<int, 3> a = std::span(_).first<3>();
auto [b,c,d] = a;
Run Code Online (Sandbox Code Playgroud)
但它不起作用https://godbolt.org/z/nhrYn65dW
然而,从P1024 std::span 的可用性增强看来,这应该是合法的
添加对固定大小跨度的结构化绑定支持?一致同意
是否可以使用结构化绑定语法确定在方括号中指定的变量名称数量,以匹配简单右侧的数据成员数量struct?
我想创建通用库的一部分,它使用结构化绑定将任意类分解为其组成部分.目前没有可变版本的结构化绑定(并且,我认为,不能用于当前提出的语法),但我首先想到的是对一些函数进行一组重载decompose(),它将struct参数分解为一组成分.decompose()应该通过参数的数量(即struct数据成员)来重载.目前constexpr if 语法也可以用来发送它.但是,我如何sizeof...为上述目的模拟类似于运算符的东西?我不能auto [a, b, c]在SFINAE结构中的某处使用语法,因为它是一个分解声明和AFAIK任何声明都不能在里面使用decltype,我也不能在lambda函数体中使用它,因为lambda函数也不能在模板参数中使用.
当然我想拥有内置运算符(语法类似于sizeof[] S/ sizeof[](S)for class S),但是类似下面的东西也是可以接受的:
template< typename type, typename = void >
struct sizeof_struct
{
};
template< typename type >
struct sizeof_struct< type, std::void_t< decltype([] { auto && [p1] = std::declval< type >(); void(p1); }) > >
: std::integral_constant< std::size_t, 1 >
{
};
template< typename type >
struct sizeof_struct< …Run Code Online (Sandbox Code Playgroud) c++ type-traits variadic-templates c++17 structured-bindings
据我了解,C++17 不禁止 lambda 表达式捕获结构化绑定。以下内容被 接受gcc但被拒绝clang,但cppreference声称 lambdas 无法捕获结构化绑定。
int arr[] {0, 1};
auto& [a, b] = arr;
auto foo = [&] { b = 9; }; // capturing structured bindings
Run Code Online (Sandbox Code Playgroud)
或者是clang或gcc不符合的?
cppreference 将行为标记为 C++17 的一部分是否错误?
考虑以下代码:
#include <utility>
#include <type_traits>
#include <cstddef>
#include <iostream>
template <typename>
struct A
{
void get() {} // #1
};
template <typename ...Ts>
struct B : A<Ts>... {};
template <typename ...Ts>
struct std::tuple_size<B<Ts...>> : std::integral_constant<std::size_t, 2> {};
template <std::size_t I, typename ...Ts>
struct std::tuple_element<I, B<Ts...>>
{
using type = int;
};
template <std::size_t I, typename ...Ts>
constexpr int get(B<Ts...>) // #2
{
return 2;
}
int main()
{
B<double, long long> b;
auto [x, y] = b;
std::cout << x …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++17 ×7
stdtuple ×2
c++20 ×1
if-constexpr ×1
qualifiers ×1
std ×1
type-traits ×1
unique-ptr ×1