让我们从一个最小的例子开始:
#include <utility>
int main()
{
auto [a, b] = std::pair(1, 'A');
return a;
}
Run Code Online (Sandbox Code Playgroud)
与GCC 7.3编译通过-std=c++17,并-Wunused-variable,并运行它:
<source>: In function 'int main()':
<source>:5:15: warning: unused variable 'b' [-Wunused-variable]
auto [a, b] = std::pair(1, 'A');
^
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会可能正确报告缺席使用b,但错误地将其称为变量.引用[dcl.struct.bind]/1:
结构化绑定声明将标识符列表的标识符 v0,v1,v2,... 引入为结构化绑定的名称([basic.scope.declarative]).
所以b显然不是变量,而是名称.使用Clang 6.0.0编译相同的代码,并使用相同的标志,我们不会得到任何警告.return a;从代码中删除语句:
#include <utility>
int main()
{
auto [a, b] = std::pair(1, 'A');
// return a;
}
Run Code Online (Sandbox Code Playgroud)
并使用Clang再次编译它,我们得到:
<source>:5:10: warning: unused variable …Run Code Online (Sandbox Code Playgroud) 我正在使用Windows 10,Visual Studio 2017 v15.7.1 /std:c++latest /permissive-
这个带结构化绑定的简单代码将无法编译:
auto [a, b] = func1(x, y, z); // auto func1() -> std::tuple<double, double, double>
[a, b] = func2(x, y, z); // same signature as func2
Run Code Online (Sandbox Code Playgroud)
说E1277 attributes are not allowed here.
下面的代码也不会编译,同样的错误
double a, b;
[a, b] = func1(x, y, z);
[a, b] = func2(x, y, z);
Run Code Online (Sandbox Code Playgroud)
码
auto [a, b] = func1(x, y, z);
auto [a, b] = func2(x, y, z);
Run Code Online (Sandbox Code Playgroud)
也不会编译,理所当然地抱怨重新定义.
它编译的唯一方法是
auto [a1, b1] = func1(x, y, …Run Code Online (Sandbox Code Playgroud) 代码如下
#include <tuple>
int main()
{
auto [a] = std::make_tuple(1);
return [a]() -> int { return a; }();
}
Run Code Online (Sandbox Code Playgroud)
在 clang 12 中产生错误:
<source>:6:13: error: 'a' in capture list does not name a variable
return [a]() -> int { return a; }();
<source>:6:34: error: reference to local binding 'a' declared in enclosing function 'main'
return [a]() -> int { return a; }();
Run Code Online (Sandbox Code Playgroud)
然而,Visual Studio 2019 和 gcc 11 都-std=c++20 -Wall -Wextra -pedantic-errors接受它。https://gcc.godbolt.org/z/jbjsnfWfj
所以它们仍然违反了结构化绑定永远不是变量名称的规则,使它们永远无法捕获?
通常 decltype 保留 ref 限定符
auto a = 0;
auto& a_ref = a;
static_assert(std::is_reference_v<decltype(a_ref)>);
Run Code Online (Sandbox Code Playgroud)
但当它的参数是从结构化绑定获得时显然不是
auto a = 0;
auto& a_ref = a;
static_assert(std::is_reference_v<decltype(a_ref)>);
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/qWT574fr9
我很确定,i并且d是这里的参考。它们应该是根据旧的新事物,智能感知是这样告诉我的。
理论上是否可以添加语言功能以将结构解压到函数实际参数列表中?我的意思是以下内容。
template< typename ...Ts >
void f(Ts... values) { (std::cout << ... << values) << std::endl; }
struct S { int a; char c; double d; };
S s{1, '2', 3.0};
f([s]);
void g(int, int, int) {}
g([s]); // warning about narrowing conversion
void h(int &, int &, int &) {}
h([s]); // hard error ("cannot bind to...")
Run Code Online (Sandbox Code Playgroud)
处理成员数量未知的合适结构会很方便。因为由于缺乏模板上下文,当前的结构化绑定无法“解压”未知数量的组件(例如 )的结构,而模板上下文只能处理可变数量的类型/值。auto... [x] = s;operator ...
这种方式有什么缺点?
是否可以使用现有的变量作为与之相关的返回值的目标structured bindings?
auto f()
{
return std::make_tuple(1,2.2);
}
int main()
{
int x;
double z;
[ x, z ] = f(); // Did not work in gcc 7.1
// structured bindings only work with "new" vars?
auto [a, b] = f(); // works fine
}
Run Code Online (Sandbox Code Playgroud) 我有以下测试用例:
testcase("[room] exits") {
auto [center, east, north, south, west] = make_test_rooms();
check_eq(center->east(), east);
check_eq(center->north(), north);
check_eq(center->south(), south);
check_eq(center->west(), west + 1);
}
Run Code Online (Sandbox Code Playgroud)
当我编译它时,clang ++(clang版本5.0.1(标签/ RELEASE_501/final))报告:
room.cpp:52:7: note: Value stored to '[center, east, north, south, west]' during its initialization is never read
Run Code Online (Sandbox Code Playgroud)
在上面的代码,testcase和check_eq用于定义的宏的文档测试单元测试包展开后DOCTEST_TEST_CASE()(某种自注册变量+函数对)和DOCTEST_CHECK_EQ(基本上,"断言== B"魔术带处理).
我知道这段代码正在执行,因为这west + 1是故意引入的错误.当我运行我的测试时,我得到一个像这样的失败消息:
===============================================================================
/.../room.cpp(51)
TEST CASE: [room] exits
/.../room.cpp(57) ERROR!
CHECK_EQ( center->west(), west + 1 )
with expansion:
CHECK_EQ( 0x00007fd6f1d011a0, 0x00007fd6f1d011f8 )
Run Code Online (Sandbox Code Playgroud)
据我所见,我使用结构化绑定中的所有值: …
结构化绑定功能表示,如果tuple_size模板是完整类型,它会像分解一样使用元组.如果std::tuple_size在程序中的某一点是给定类型的完整类型并且在另一点未完成,会发生什么?
#include <iostream>
#include <tuple>
using std::cout;
using std::endl;
class Something {
public:
template <std::size_t Index>
auto get() {
cout << "Using member get" << endl;
return std::get<Index>(this->a);
}
std::tuple<int> a{1};
};
namespace {
auto something = Something{};
}
void foo() {
auto& [one] = something;
std::get<0>(one)++;
cout << std::get<0>(one) << endl;
}
namespace std {
template <>
class tuple_size<Something> : public std::integral_constant<std::size_t, 1> {};
template <>
class tuple_element<0, Something> {
public:
using type = int; …Run Code Online (Sandbox Code Playgroud) c++ one-definition-rule undefined-behavior c++17 structured-bindings
简洁版本:
我希望能够将结构转换为元组。至少是类型。在下面的代码中,convertToTuple函数不起作用,因为可变参数不能在结构化绑定中使用(据我所知)。关键行是:auto& [values...] = value;
struct Vec3 {
float x;
float y;
float z;
};
template <typename T>
auto structToTuple(T &value) {
auto& [values...] = value; //doesn't work
return std::make_tuple<decltype(values)...>(values...);
}
Vec3 v;
std::tuple<float, float, float> t = structToTuple(v);
Run Code Online (Sandbox Code Playgroud)
基本上,我需要的是一种将自定义结构的类型转换为元组的方法,其中包含结构中的所有类型。例如:
struct Ray {Vec3, Vec3} -> std::tuple<
std::tuple<float, float, float>,
std::tuple<float, float, float>>;
Run Code Online (Sandbox Code Playgroud)
详细问题:
我想创建一个模板化函数,它将一个类型或类型列表作为模板参数并生成一个纹理列表,每个纹理包含一个项目。其他函数可以对纹理列表进行采样,并将这些值打包在一起以返回相同的类型。例如,如果我有一个类型:
std::pair<std::tuple<int, int>, int> value;
std::tuple<Texture<int, int>, Texture<int>> tex = createTexture(value);
std::pair<std::tuple<int, int>, int> thisshouldwork = sample(tex);
Run Code Online (Sandbox Code Playgroud)
上面的代码只是我想要做的一个简单示例,而不是我的实际代码。在这种情况下,将创建 2 个纹理,一个纹理将包含元组中的两个 int,另一个纹理将包含单个 int 类型。我的目的是将纹理处理隐藏在接口后面,我可以在纹理中存储任意值(只要它由一些简单类型组成),然后将其上传到 GPU …
我想为类模板的内部类提供结构化绑定。我怎样才能专门研究std::tuple_size这个内部类?
我无法对数据成员使用结构化绑定,因为内部类可能是与该功能不兼容的类型。所以我需要提供类似元组的结构化绑定。为了向内部类提供这样的功能,我需要部分专注std::tuple_size于namespace std. 问题是我得到了参数(外部类)的非推导上下文。T
我知道我可以将内部类放在全局命名空间中,从而解决每个问题,但是有什么方法可以得到相同的结果,保持类内部?
#include <tuple>
template<typename T>
class Collection
{
public:
struct Element
{
int id;
T actual_element;
};
//...
};
namespace std
{
template<typename T>
struct tuple_size<typename Collection<T>::Element> // Error! Non-deduced context
: std::integral_constant<std::size_t, 2> {};
}
//Collection iterators...
int main()
{
Collection<int> collection;
for (auto & [id, element] : collection) //what I'd like to achieve
//do some stuff...
}
Run Code Online (Sandbox Code Playgroud) c++ ×10
c++17 ×8
c++20 ×1
clang++ ×1
decltype ×1
gcc ×1
stdtuple ×1
templates ×1
type-traits ×1
visual-c++ ×1