Can someone please explain the indices trick ?
The problem is: we have a std::tuple<T1, T2, ...>
and we have some function f
that we can to call on each element, where f
returns an int
, and we want to store those results in an array.
Let's start with a concrete case:
template <typename T> int f(T ) { return sizeof(T); }
std::tuple<int, char, double> tup{42, 'x', 3.14};
std::array<int, 3> arr{ f(std::get<0>(tup)),
f(std::get<1>(tup)),
f(std::get<2>(tup)) );
Except writing out all those get
s is inconvenient and redundant at best, error-prone at worst.
First we need to include the utility header for std::index_sequence
and std::make_index_sequence
:
#include <utility>
Now, let's say we had a type index_sequence<0, 1, 2>
. We could use that to collapse that array initialization into a variadic pack expansion:
template <typename Tuple, size_t... Indices>
std::array<int, sizeof...(Indices)>
call_f_detail(Tuple& tuple, std::index_sequence<Indices...> ) {
return { f(std::get<Indices>(tuple))... };
}
That's because within the function, f(std::get<Indices>(tuple))...
gets expanded to f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple))
. Which is exactly what we want.
The last detail of the problem is just generating that particular index sequence. C++14 actually gives us such a utility named make_index_sequence
template <typename Tuple>
std::array<int, std::tuple_size<Tuple>::value>
call_f(Tuple& tuple) {
return call_f_detail(tuple,
// make the sequence type sequence<0, 1, 2, ..., N-1>
std::make_index_sequence<std::tuple_size<Tuple>::value>{}
);
}
whereas the article you linked simply explains how one might implement such a metafunction.
Bare
is probably something like, from Luc Danton's answer:
template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
multidimensional array initialization using indices trick
This can be made a lot easier by changing the code to access the array, not the indices generation. What you basically want is a 1D to 2D access mapping.
Normally, people need it the other way around (2D to 1D), when they implement a 2D array in terms of a 1D array†:
template<class T, unsigned M, unsigned N>
struct md_array{
T elems[M * N]; // same layout as 'T elems[M][N];'
};
The formula to get the 1D index i
from the 2D index (x,y)
is then i == x * N + y
. We can explain this if we imagine our 1D elems
from above as a 2D array (using M == 2
and N == 3
):
0, 1, 2, 3, 4, 5 // indices (i)
[a, b, c, d, e, f]
v // we want them as M (2) packs of N (3) elements
0, 1, 2 0, 1, 2 // element indices (y)
[a, b, c] [d, e, f]
\___0___/ \___1___/ // pack indices (x)
v // fusing the packs back together, we can see that we have
// a constant offset for the packs, which is the N (3) times x
0*3+0, 0*3+1, 0*3+2, 1*3+0, 1*3+1, 1*3+2
[ a, b, c, d, e, f ]
Thus, we get i == x * N + y
. We now need to solve this formula not for i
but for x
and y
. For x
, it's rather easy (using math notation):
i = x * N + y | -y
i - y = x * N | *(1/N)
i - y
----- = x
N
So x == (i - y) / N
. Now, sadly, I don't know how to solve this for y
using pure math, but we don't need that. Taking a look at the element indices, we can see that they wrap around N
, and that can easily be done using the modulo operator. Thus, y == i % N
.
Now we can implement a method that takes a linear index i
and returns the element at the solved (x, y)
from that:
template<unsigned I>
T& get(){ constexpr auto y = I % 3; return array[(I-y)/3][y]; }
and generalizing that:
template<unsigned I>
T& get(){ constexpr auto y = I % N, x = (I-y)/N; return array[x][y]; }
Using constexpr
to ensure that all the computation is done at compile-time.
Now you can simply write assign
as follows:
template<unsigned... Is, class... U>
void assign(indices<Is...>, U... args)
{
[](...){}((get<Is>() = args)...);
}
Q.E.D. (Live example.)
† Now, you can make this easier on yourself by actually implementing the 2D array as a 1D array. :) This way, you can straight-forwardly use (array[Is] = args)...
and for the other cases use a simple access function that does the mapping:
T& get(unsigned x, unsigned y){ return array[x * N + y]; }
Live example.
How do I get index of elements in parameter pack
It seems to me (if you can use at least C++14) a work for a delegating constructor
template <typename ... Ts>
class ClassA
{
private:
template <std::size_t ... Is>
ClassA (std::index_sequence<Is...> const &, Ts ... ts)
: tup { std::make_tuple(ts, Is) ... }
{ }
public:
ClassA (Ts ... ts)
: ClassA(std::make_index_sequence<sizeof...(Ts)>{}, ts...)
{ }
std::tuple<std::tuple<Ts, std::size_t>...> tup;
};
In C++11 this doesn't works because std::index_sequence
and std::make_index_sequence
are available only starting from C++14 but it isn't difficult to find (or develop) C++11 substitutes.
In numpy, how to create an array of the indices of the elements in a source array as they are found in a destination array?
Here is what I believe is the "direct" way:
# find order of src and dst
so = src.ravel().argsort()
do = dst.ravel().argsort()
# allocate combined map
tot = np.empty_like(src)
# next line is all you need to remember
tot.ravel()[so] = do
# go back to 2D indexing
indices = np.unravel_index(tot,dst.shape)
# check
dst[indices]
# array([[8, 1],
# [2, 4]])
indices
# (array([[1, 0],
# [1, 0]]), array([[0, 0],
# [1, 1]]))
Related Topics
How to Make Visual Studio Use the Native Amd64 Toolchain
C++ Inheritance - Inaccessible Base
Getting "Source Type Is Not Polymorphic" When Trying to Use Dynamic_Cast
How to Create a Sparse Array in C++
How to Dynamically Allocate a Matrix
Is F(Void) Deprecated in Modern C and C++
C++11: Compile Time Calculation of Array
C++ Data Alignment /Member Order & Inheritance
Sse, Intrinsics, and Alignment
Why Is There No Transform_If in the C++ Standard Library
What Is Decltype with Two Arguments
Do Rvalue References Allow Dangling References
What Is Going on with 'Gets(Stdin)' on the Site Coderbyte
C++ Compile Time Error: Expected Identifier Before Numeric Constant
Initialization: Parenthesis VS. Equals Sign
How to Make a Variadic MACro for Std::Cout