C++17 Structured Binding Tutorial
C++17 Structured Binding Tutorial
Summary
Structured binding is a feature released in C++17 that easily allows a function to return multiple values. This is a quick summary of the various ways to use it, including in a device function. Note that in C++17 structured binding returns cannot be const
, this was added in C++17.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Demonstration of C++17 structured binding in host and device code. Compile with
// `nvcc -std=c++17 structured-binding.cu` on CUDA on
// 'hipcc -g -std=c++17 structured-binding.cu` on HIP
#include <iostream>
#include <tuple>
#include <vector>
#ifdef __HIP__
#include<hip/hip_runtime.h>
#endif //HIP
// =============================================================================
// The classic method of returning multiple values is to pass them to the
// function by reference and set them within the function. This can be slow and
// unclear. C++17 structured binding attempts to address this and gives you
// several options in implementation.
// More details on the reasons that structured binding is often faster can be
// found [here](https://www.nexthink.com/blog/c17-function/)
// =============================================================================
// =============================================================================
// Returning a std::pair is fast since it doesn't use the stack if the return
// is <= 128 bits. Requires C++17 and can't be overloaded.
// Functions that return std::pair or std::tuple can either be of type `auto` or
// have their type explicitely declared. Both are shown here
auto pairReturn()
{
return std::make_pair(7,8);
}
// =============================================================================
// =============================================================================
// Uses stack. Slower than returning a local struct or a std::pair but easier to
// add values to
std::tuple<int, int, double> tupleReturn()
{
return {3,4,17.4};
}
// =============================================================================
// =============================================================================
// Returning a local struct is fast since it doesn't use the stack if the return
// is <= 128 bits. Requires C++17 and can't be overloaded
auto __device__ __host__ localStructReturn()
{
struct returnStruct
{
int ret1, ret2;
};
return returnStruct{5,6};
}
// =============================================================================
// =============================================================================
__global__ void printValues()
{
if (threadIdx.x == 0)
{
auto [devA, devB] = localStructReturn();
printf("devA = %i\ndevB = %i\n", devA, devB);
}
}
// =============================================================================
int main()
{
// Simple structured binding from array. Does not work for std::vector since
// it's details are not known at compile time. It does work with std::array
// though
int a[2] = {1,2};
auto [b,c] = a;
std::cout << b << std::endl;
std::cout << c << std::endl;
auto [d,e,dbl] = tupleReturn();
std::cout << d << std::endl;
std::cout << e << std::endl;
std::cout << dbl << std::endl;
auto [f,g] = localStructReturn();
std::cout << f << std::endl;
std::cout << g << std::endl;
auto [h,i] = pairReturn();
std::cout << h << std::endl;
std::cout << i << std::endl;
#ifdef __HIP__
hipLaunchKernelGGL(printValues, 1,1,0,0);
auto ignore = hipDeviceSynchronize();
#else // CUDA
printValues<<<1,1>>>();
cudaDeviceSynchronize();
#endif //HIP
return 0;
}
This post is licensed under CC BY 4.0 by the author.