Advertisement

C++ template parameter pack expansion

Started by June 20, 2022 01:51 PM
3 comments, last by Juliean 2 years, 5 months ago

I've been thinking for hours about how to expand the template parameter pack for generating a 2D array, but haven't come up with anything. Maybe one of you can guess? So far, it looks impossible to me.

The result should be as follows:

#include <utility>

int Values[3][3]{ };

void Generate()
{
	int result[3][3]
	{
		{ Values[0][0] + 1, Values[0][1] + 1, Values[0][2] + 1 },
		{ Values[1][0] + 1, Values[1][1] + 1, Values[1][2] + 1 },
		{ Values[2][0] + 1, Values[2][1] + 1, Values[2][2] + 1 }
	};
}

int main()
{
	
}

Let's try to do it with a template:

One of my bad tries:

#include <utility>

int Values[3][3]{ };

template<std::size_t... Indices1, std::size_t... Indices2>
void Generate(std::index_sequence<Indices1...>, std::index_sequence<Indices2...>)
{
	int result[3][3]
	{
		(Indices1, { (Values[Indices1][Indices2] + 1)... })... // ERROR
	};
}

int main()
{
	Generate(std::make_index_sequence<3>{ }, std::make_index_sequence<3>{ });
}

There were more tries, but I'm ashamed to even show them.

This can be solved by using std::array, or by declaring an empty array and filling it with loops, etc. Please don't write such answers. In this case, I'm wondering if it's possible to do this with standard arrays or not.

I'll have two number 9s, a number 9 large, a number 6 with extra dip, a number 7, two number 45s, one with cheese, and a large soda.

template<std::size_t... Indices>
void GenerateImpl(int* array, std::size_t index, std::index_sequence<Indices...>)
{
    // TODO: missing "+ 1" to Values here
	((array[Indices] = Values[index][Indices]), ...);
}

template<std::size_t... Indices1, std::size_t... Indices2>
void Generate(std::index_sequence<Indices1...>, std::index_sequence<Indices2...> seq2)
{
	int result[3][3];

	(GenerateImpl(result[Indices1], Indices1, seq2), ...);
}

int main()
{
	Generate(std::make_index_sequence<3>{ }, std::make_index_sequence<3>{ });
}

Thats the best I can come up with. This doesn't use inline-initialization, however it should make no difference in terms of execution, so if you can live with the array being initialized in a different function, there you go. As explanation, this splits the value-access in two separate fold-expression, where the result of the first is passed as one “index” parameter into the second function, which then expands the leftover sequence to write the values.

Advertisement

Juliean said:

template<std::size_t... Indices>
void GenerateImpl(int* array, std::size_t index, std::index_sequence<Indices...>)
{
    // TODO: missing "+ 1" to Values here
	((array[Indices] = Values[index][Indices]), ...);
}

template<std::size_t... Indices1, std::size_t... Indices2>
void Generate(std::index_sequence<Indices1...>, std::index_sequence<Indices2...> seq2)
{
	int result[3][3];

	(GenerateImpl(result[Indices1], Indices1, seq2), ...);
}

int main()
{
	Generate(std::make_index_sequence<3>{ }, std::make_index_sequence<3>{ });
}

Thats the best I can come up with. This doesn't use inline-initialization, however it should make no difference in terms of execution, so if you can live with the array being initialized in a different function, there you go. As explanation, this splits the value-access in two separate fold-expression, where the result of the first is passed as one “index” parameter into the second function, which then expands the leftover sequence to write the values.

I was wondering if it was possible to do this, as you called it, through "inline-initialization" (is it really impossible to do this with C++ syntax?). Of course, if we don't use initialization right away, there are many options on how this can be implemented.

This can be solved by using std::array, or by declaring an empty array and filling it with loops, etc.

Even in the case of your code, it would be much better to replace this with a loop, as I wrote above. It will unroll anyway.

I'll have two number 9s, a number 9 large, a number 6 with extra dip, a number 7, two number 45s, one with cheese, and a large soda.

Ok, I think you might be able to do it by creating a joint index_sequence in the size Indices1*Indices2, then doing

const auto Indices12 = std::make_index_sequence<sizeof...(Indices1) * sizeof...(Indices2)>;

int result[3][3]
{
	getValue(Indices12)... 
};

And inside getValue you would eigther calculate the x/y-values back from the 0…8-value, or access the 2d-array as a 1d-array with that one index.

I don't have the time to produce a sample, but are you getting what I'm going for? Think you are not getting any closer than that unless a new standard introduces some new syntax.

This topic is closed to new replies.

Advertisement