Can multiple parameter packs be expanded in a single expression? - c++

I want to get a matrix from two parameter packs like the following:
template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};
void Print( int n ){ std::cout << n << std::endl; }
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
using expander = int[];
// No idea which syntax should be used here:
expander{ 0,((void)Print(n1...*n2),0)... };
}
};
int main()
{
Multi< N<1,2,3,4>, N< 10,20> >{};
}
The result should be
10 20 30 40 20 40 60 80
How can I do this?

No need to use the dummy arrays when you have fold expressions.
The naive (Print(n1 * n2), ...); wouldn't work (it expects the packs to have the same size, and would print N numbers instead of N2).
You need two nested fold expressions. In the inner one, you can prevent one of the packs from being expanded by passing it as a lambda parameter.
([](int n){(Print(n1 * n), ...);}(n2), ...);

This is not single expression, but you can expand it and use for loop
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
for(auto j : {n2...})
for(auto i : {n1...})
std::cout << i*j << '\n';
}
};
WandBox

I kind of assume that the output in your code is to check the compile time evaluation, since the output to std::cout only works at runtime.
Another option is not to use structs but to use constexpr functions,
they look more like regular c++ code. And you van validate the correctness at compile time using static_asserts. I did add some output at the end of my example
live demo here : https://onlinegdb.com/iNrqezstg
#include <array>
#include <iostream>
template<int... n>
constexpr auto array()
{
return std::array<int,sizeof...(n)>{n...};
};
template<std::size_t N, std::size_t M>
constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
{
std::array<int, N* M> result{};
std::size_t index{ 0 };
for (std::size_t n = 0; n < N; n++)
{
for (std::size_t m = 0; m < M; m++)
{
result[index] = arr1[n] * arr2[m];
++index;
}
}
return result;
}
template<typename container_t>
void show(const char* msg, const container_t& values)
{
std::cout << msg << " : ";
bool comma{ false };
for (const auto& value : values)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
int main()
{
constexpr auto arr1 = array<1, 2, 3, 4>();
constexpr auto arr2 = array<10, 20>();
constexpr auto result = multiply(arr1, arr2);
static_assert(arr1[0] == 1, "");
static_assert(arr2[1] == 20, "");
static_assert(result[0] == 10, "");
static_assert(result[1] == 20, "");
static_assert(result[6] == 40, "");
show("arr1", arr1);
show("arr2", arr2);
show("result", result);
return 0;
}

Related

How can I implement a constexpr N-way set_union (deduplicated merge)

I have a bunch of structs holding pre-sorted std::arrays of varying number of size_ts. As a toy example, suppose we've got the following three structs:
struct F_A { static constexpr std::array<size_t, 4> bounds = { 0, 100, 200, 300 }; };
struct F_B { static constexpr std::array<size_t, 5> bounds = { 0, 125, 250, 300, 500 }; };
struct F_C { static constexpr std::array<size_t, 4> bounds = { 100, 250, 300, 301 }; };
The goal is to perform the equivalent of an N-way std::set_union at compilation time; e.g., given the above structs, I want to be able to write
constexpr auto bounds = merge_bounds<F_A,F_B,F_C>();
and end up with bounds as a constexpr std::array<size_t, 8> containing values 0, 100, 125, 200, 250, 300, 301, 500.
It was pretty easy to make this work for merging the bounds arrays from a pair of structs; however, I am at a bit of a loss regarding how best to generalize this to use variadic templates and parameter packs. To get the version with pairs working, I resort to first "simulating" a merge to determine how long the merged array will be before actually doing the merge, but this approach gets awfully hairy when combining with parameter packs. (I suspect even my code for pairs is far less elegant than it would be if I had a better handle on some of the relevant language features...)
Here's an MWE demonstrating my functioning code for pairs:
#include <cstdlib>
#include <iostream>
#include <array>
struct F_A { static constexpr std::array<size_t, 4> bounds = { 0, 100, 200, 300 }; };
struct F_B { static constexpr std::array<size_t, 5> bounds = { 0, 125, 250, 300, 500 }; };
struct F_C { static constexpr std::array<size_t, 4> bounds = { 100, 250, 300, 301 }; };
template <typename F0, typename F1>
inline static constexpr auto merged_size()
{
constexpr auto bnd0 = F0::bounds;
constexpr auto bnd1 = F1::bounds;
size_t i = 0, i0 = 0, i1 = 0;
while (i0 < bnd0.size() && i1 < bnd1.size())
{
if (bnd0[i0] < bnd1[i1]) { i++; i0++; }
else if (bnd0[i0] > bnd1[i1]) { i++; i1++; }
else { i++; i0++; i1++; }
}
while (i0 < bnd0.size()) { i++; i0++; }
while (i1 < bnd1.size()) { i++; i1++; }
return i;
}
template <typename F0, typename F1, size_t N = merged_size<F0,F1>()>
inline static constexpr auto merge_bounds()
{
std::array<size_t, N> merged = { 0 };
constexpr auto bnd0 = F0::bounds;
constexpr auto bnd1 = F1::bounds;
size_t i = 0, i0 = 0, i1 = 0;
while (i0 < bnd0.size() && i1 < bnd1.size())
{
if (bnd0[i0] < bnd1[i1]) { merged[i++] = bnd0[i0++]; }
else if (bnd0[i0] > bnd1[i1]) { merged[i++] = bnd1[i1++]; }
else { merged[i++] = bnd0[i0++]; i1++; }
}
while (i0 < bnd0.size()) { merged[i++] = bnd0[i0++]; }
while (i1 < bnd1.size()) { merged[i++] = bnd1[i1++]; }
return std::move(merged);
}
int main(int argc, char * argv[])
{
std::cout << merged_size<F_A,F_B>() << "," << merged_size<F_B,F_C>() << "," << merged_size<F_A,F_C>() << std::endl;
for (auto i : merge_bounds<F_A,F_B>()) std::cout << i << " ";
std::cout <<"\n";
for (auto i : merge_bounds<F_B,F_C>()) std::cout << i << " ";
std::cout <<"\n";
for (auto i : merge_bounds<F_A,F_C>()) std::cout << i << " ";
std::cout <<"\n";
return 0;
}
How can I generalize merge_bounds to allow an arbitrary number of such structs to be specified as template parameters?
Embrace values.
template<class T, std::size_t N>
struct partial_array:std::array<T,N>{
std::size_t partial=N;
constexpr std::size_t size()const{return partial;}
constexpr T* end()const{return this->begin()+partial;}
//etc
};
template<class T, std::size_t N, std::size_t M, std::size_t...Ms>
constexpr partial_array<T,N+M> merge(partial_array<T,N>,partial_array<T,M>);
template<class T, std::size_t N, std::size_t M>
constexpr partial_array<T,N+(M+Ms...)> merge(partial_array<T,N> a,partial_array<T,M> b, partial_array<T,Ms>... cs){
return merge( a, merge(b,cs...) );
}
Now you just take the arrays, turn them to partial arrays, merge them. The result is a constexpr partial array with a constexpr size.
Convert that constexpr size into an array bounds, and copy the data over.
template <class...Ts>
constexpr auto merge_bounds() {
constexpr auto merged = merge(partial_array{Ts::bounds}...);// do some magic to make this compile; maybe deduction guilds and a ctor?
std::array<T,merged.size()> retval = merged; // add an operator std::array<T,X> to partial array
return retval;
}
code is probably full of typos, but I hope you get the idea.

Obfuscate std::array using constexpr

I'm looking for a small function that is able to transform a std::array by adding increasing values. The function must be a compile time function.
I was able to write a small constexpr function which does so for an array of length 3, but I was unable to generalize it to std::arrays of arbitrary lengths. I also failed to generalize it to contain something different than chars.
Does anyone knows how to do it?
#include <array>
#include <iostream>
#include <valarray>
constexpr std::array<char,3> obfuscate(const std::array<char,3>& x) {
return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}
/* Won't compile
template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/
std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
for (auto i = 0; i < 3; i++) {
str << x.at(i);
}
return str;
}
int main(int argc, char** args) {
std::array<char, 3> x{ 'a','b','c' };
std::cout << x << std::endl;
std::cout << obfuscate(x) << std::endl;
// std::cout << obfuscate<3>(x) << std::endl;
}
You can use std::index_sequence:
template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}
template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
return helper(x, std::make_index_sequence<N>{});
}
There are a few methods that use tuple packs, these are great except that MSVC has a performance problem compiling large strings.
I've found this compromise works well in MSVC.
template<typename I>
struct encrypted_string;
template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
std::array<char, sizeof...(I)+1> buf;
constexpr static char encrypt(char c) { return c ^ 0x41; }
constexpr static char decrypt(char c) { return encrypt(c); }
constexpr explicit __forceinline encrypted_string(const char* str)
: buf{ encrypt(str[I])... } { }
inline const char* decrypt()
{
for (size_t i = 0; i < sizeof...(I); ++i)
{
buf[i] = decrypt(buf[i]);
}
buf[sizeof...(I)] = 0;
return buf.data();
}
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)
And somewhere later
auto stringo = enc(R"(
kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
int rows, int cols) {
int x = get_global_id(0);
int y0 = get_global_id(1);
if (x < cols) {
int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
Beta[srcBeta_index] = A[srcA_index];
}
}
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());
You can see this guy's talk for more sophisticated methods:
https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf

How to generate nested loops at compile time

I have an integer N which I know at compile time. I also have an std::array holding integers describing the shape of an N-dimensional array. I want to generate nested loops, as described bellow, at compile time, using metaprogramming techniques.
constexpr int N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
auto f = [/* accept object which uses coords */] (auto... coords) {
// do sth with coords
};
// This is what I want to generate.
for(int i = 0; i < shape[0]; i++) {
for(int j = 0; j < shape[1]; j++) {
for(int k = 0; k < shape[2]; k++) {
for(int l = 0; l < shape[3]; l++) {
f(i,j,k,l) // object is modified via the lambda function.
}
}
}
}
Note the parameter N is known at compile time but might change unpredictably between compilations, hence I can't hard code the loops as above. Ideally the loop generation mechanism will provide an interface which accepts the lambda function, generates the loops and calls the function producing the equivalent code as above. I am aware that one can write an equivalent loop at runtime with a single while loop and an array of indices, and there are answers to this question already. I am, however, not interested in this solution. I am also not interested in solutions involving preprocessor magic.
Something like this (NOTE: I take the "shape" as a variadic template argument set..)
#include <iostream>
template <int I, int ...N>
struct Looper{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
Looper<N...>()(f, x..., i);
}
}
};
template <int I>
struct Looper<I>{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
f(x..., i);
}
}
};
int main()
{
int v = 0;
auto f = [&](int i, int j, int k, int l) {
v += i + j + k + l;
};
Looper<1, 3, 5, 2>()(f);
auto g = [&](int i) {
v += i;
};
Looper<5>()(g);
std::cout << v << std::endl;
}
Assuming you don't want total loop unrolling, just generation of i, j, k etc. argument tuples for f:
#include <stdio.h>
#include <utility> // std::integer_sequence
template< int dim >
constexpr auto item_size_at()
-> int
{ return ::shape[dim + 1]*item_size_at<dim + 1>(); }
template<> constexpr auto item_size_at<::N-1>() -> int { return 1; }
template< size_t... dim >
void call_f( int i, std::index_sequence<dim...> )
{
f( (i/item_size_at<dim>() % ::shape[dim])... );
}
auto main()
-> int
{
int const n_items = ::shape[0]*item_size_at<0>();
for( int i = 0; i < n_items; ++i )
{
call_f( i, std::make_index_sequence<::N>() );
}
}
I suppose this is exactly what you asked for:
#include <array>
#include <iostream>
constexpr int N{4};
constexpr std::array<int, N> shape {{1,3,5,2}};
// Diagnositcs
template<typename V, typename ...Vals>
struct TPrintf {
constexpr static void call(V v, Vals ...vals) {
std::cout << v << " ";
TPrintf<Vals...>::call(vals...);
}
};
template<typename V>
struct TPrintf<V> {
constexpr static void call(V v) {
std::cout << v << std::endl;
}
};
template<typename ...Vals>
constexpr void t_printf(Vals ...vals) {
TPrintf<Vals...>::call(vals...);
}
// Unroll
template<int CtIdx, typename F>
struct NestedLoops {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[CtIdx]; ++i) {
NestedLoops<CtIdx + 1, F>::call(f, idx..., i);
}
}
};
template<typename F>
struct NestedLoops<N-1, F> {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[N-1]; ++i) {
f(idx..., i);
}
}
};
template<typename F>
void nested_loops(const F& f) {
NestedLoops<0, F>::call(f);
}
int main()
{
auto lf = [](int i, int j, int k, int l) {
t_printf(i,j,k,l);
};
nested_loops(lf);
return 0;
}
Another variant of the same thing:
template <size_t shape_index, size_t shape_size>
struct Looper
{
template <typename Functor>
void operator()(const std::array<int, shape_size>& shape, Functor functor)
{
for (int index = 0; index < shape[shape_index]; ++index)
{
Looper<shape_index + 1, shape_size>()
(
shape,
[index, &functor](auto... tail){ functor(index, tail...); }
);
}
}
};
template <size_t shape_size>
struct Looper<shape_size, shape_size>
{
template <typename Functor>
void operator()(const std::array<int, shape_size>&, Functor functor)
{
functor();
}
};
template <size_t shape_size, typename Functor>
void loop(const std::array<int, shape_size>& shape, Functor functor)
{
Looper<0, shape_size>()(shape, functor);
}
Example of use:
constexpr size_t N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
void f(int i, int j, int k, int l)
{
std::cout
<< std::setw(5) << i
<< std::setw(5) << j
<< std::setw(5) << k
<< std::setw(5) << l
<< std::endl;
}
// ...
loop(shape, f);
Live demo

extract an array from another array at compile time using c++

Not sure if it's possible for more later version of c++. (I can't figure out using traditional c++ to achieve the following behaviofgr.)
For example,
If I have an array defined like this:
In the header file
struct Def {
static const int N = 5;
static const double data[N];
};
In its cpp
const double Def::data[Def::N] = {0,1,2,3,4};
Is it possible to have a template get_subarray such that
get_subarray<Def,2,0>::data will be an array of content {0,2,4}
get_subarray<Def,2,1>::data will be an array of content {1,3}
where
template<typename T, int M, int m>
struct get_phase {
// some code for the array variable data which will
// extract element from T::data for every M sample offset by index m
};
As mentioned in the comments, the OP is interested also in C++14 based solutions.
Here is one of them:
#include<functional>
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t O, typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr, std::index_sequence<I...>) {
return { std::get<I+O>(arr)... };
}
template<std::size_t B, std::size_t E, typename T, std::size_t N>
constexpr auto f(const std::array<T, N> &arr) {
return f<B>(arr, std::make_index_sequence<E-B>());
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1, 2>(a1);
static_assert(a1[1] == a2[0], "!");
}
In this case, a2 is equal to { 1 }.
It's worth it checking B and E so as to verify that E is greater than B, but the example should give an idea of what's the way to do it.
To port it to C++11:
Do not use auto as return type, but explicitly specify std::array (easy)
Search on the web one of the available C++11 implementations of integer_sequence and make_index_sequence and use it
If it's fine to be explicit about the indexes and not use a range, here is a naïve snippet that should work in C++11:
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t... I, typename T, std::size_t N>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr) {
return { std::get<I>(arr)... };
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1>(a1);
static_assert(a1[1] == a2[0], "!");
}
As in the previous example, a2 is { 1 }.
I like the skypjack's solution but it doesn't extract the requested values. skypjack's version has two parameters, "begin" and "end". The OP requested "stride" or "frequency" and "begin".
I've modified it to match the OP's requested "frequency" and "start" arguments, giving the template non-type parameters more self-explaining names, and rewriting a couple of index calculations:
#include<utility>
#include<iostream>
#include<array>
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim,
std::size_t... I>
constexpr std::array<T, sizeof...(I)>
extractHelper (const std::array<T, Dim> & arr,
std::integer_sequence<std::size_t, I...>)
{ return { { std::get<Freq*I+Start>(arr)... } }; }
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim>
constexpr auto extractSamples (const std::array<T, Dim> & arr)
{ return extractHelper<Freq, Start>
(arr, std::make_index_sequence<(Dim+Freq-1-Start)/Freq>()); }
Here is some test code:
int main()
{
constexpr std::array<int, 8> a1 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
constexpr auto e1 = extractSamples<2, 0>(a1);
constexpr auto e2 = extractSamples<2, 1>(a1);
constexpr auto e3 = extractSamples<3, 0>(a1);
constexpr auto e4 = extractSamples<3, 1>(a1);
constexpr auto e5 = extractSamples<3, 2>(a1);
std::cout << "samples<2, 0>: ";
for ( auto const & i : e1 )
std::cout << ' ' << i;
std::cout << "\nsamples<2, 1>: ";
for ( auto const & i : e2 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 0>: ";
for ( auto const & i : e3 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 1>: ";
for ( auto const & i : e4 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 2>: ";
for ( auto const & i : e5 )
std::cout << ' ' << i;
std::cout << std::endl;
return 0;
}
The output is:
samples<2, 0>: 0 2 4 6
samples<2, 1>: 1 3 5 7
samples<3, 0>: 0 3 6
samples<3, 1>: 1 4 7
samples<3, 2>: 2 5
which matches the OP's requests
Here's a solution in C++11 without additives. As usual,
compiletime recursion makes do for the lack of C++14's std::index_sequence
- in this case by recursively assembling the list of indices that
select the desired sample of the data array.
Given some:
constexpr std::array<T,N> data{{...}};
initialized ... with the Ts of your choice, then:
constexpr auto sample = get_sample<Stride,Offset>(data);
will define sample as a compiletime
std::array<T,M>
populated with the M elements of data obtained by selecting the element
at offset Offset from the start of successive Stride-sized intervals of
data.
#include <array>
#include <type_traits>
constexpr std::size_t
sample_size(std::size_t size, std::size_t stride, std::size_t off)
{
return stride == 0 ? 0 : ((size - off) / stride) +
(off + (((size - off) / stride) * stride) < size);
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) == sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return std::array<T,sample_size(Size,Stride,Off)>{{data[Is]... }};
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) != sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return
get_sample<Stride,Off,T,Size,Is...,(sizeof...(Is) * Stride) + Off>
(data);
}
By default Stride is 1 and Off is 0. The helper function sample_size
embeds the convention that if Stride is 0 you get an empty sample.
For an illustrative program, you can append:
constexpr std::array<int,5> data1{{0,1,2,3,4}};
constexpr auto sample1 = get_sample(data1);
constexpr auto sample2 = get_sample<2>(data1);
constexpr auto sample3 = get_sample<2,1>(data1);
constexpr auto sample4 = get_sample<6>(data1);
constexpr auto sample5 = get_sample<6,5>(data1);
static_assert(sample5.size() == 0,"");
constexpr std::array<float,6> data2{{1.1,2.2,3.3,4.4,5.5,6.6}};
constexpr auto sample6 = get_sample<2>(data2);
constexpr auto sample7 = get_sample<2,3>(data2);
constexpr auto sample8 = get_sample<3,2>(data2);
constexpr std::array<int,0> data3{};
constexpr auto sample9 = get_sample<0>(data3);
static_assert(sample9.size() == 0,"");
constexpr auto sample10 = get_sample<2>(data3);
static_assert(sample10.size() == 0,"");
#include <iostream>
int main()
{
std::cout << "get_sample<> of {0,1,2,3,4}\n";
for (auto const & e : sample1) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2> of {0,1,2,3,4}\n";
for (auto const & e : sample2) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2,1> of {0,1,2,3,4}\n";
for (auto const & e : sample3) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<6> of {0,1,2,3,4}\n";
for (auto const & e : sample4) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample6) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2,3> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample7) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<3,2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample8) {
std::cout << e << ' ';
}
std::cout << '\n';
return 0;
}
which reports:
get_sample<> of {0,1,2,3,4}
0 1 2 3 4
get_sample<2> of {0,1,2,3,4}
0 2 4
get_sample<2,1> of {0,1,2,3,4}
1 3
get_sample<6> of {0,1,2,3,4}
0
get_sample<2> of {1.1,2.2,3.3,4.4,5.5,6.6}
1.1 3.3 5.5
get_sample<2,3> of {1.1,2.2,3.3,4.4,5.5,6.6}
4.4 6.6
get_sample<3,2> of {1.1,2.2,3.3,4.4,5.5,6.6}
3.3 6.6
See it live
If you want to apply this to your class Def, you would redefine it in an amenable
way like:
struct Def {
static constexpr int N = 5;
static constexpr std::array<double,N> data{{0,1,2,3,4}};
};
and get your compiletime sample like:
constexpr auto s = get_sample<2,1>(Def::data);
(g++ 6.1/clang++ 3.8, -std=c++11 -Wall -Wextra -pedantic)

Simpler way to set multiple array slots to one value

I'm coding in C++, and I have the following code:
int array[30];
array[9] = 1;
array[5] = 1;
array[14] = 1;
array[8] = 2;
array[15] = 2;
array[23] = 2;
array[12] = 2;
//...
Is there a way to initialize the array similar to the following?
int array[30];
array[9,5,14] = 1;
array[8,15,23,12] = 2;
//...
Note: In the actual code, there can be up to 30 slots that need to be set to one value.
This function will help make it less painful.
void initialize(int * arr, std::initializer_list<std::size_t> list, int value) {
for (auto i : list) {
arr[i] = value;
}
}
Call it like this.
initialize(array,{9,5,14},2);
A variant of aaronman's answer:
template <typename T>
void initialize(T array[], const T& value)
{
}
template <size_t index, size_t... indices, typename T>
void initialize(T array[], const T& value)
{
array[index] = value;
initialize<indices...>(array, value);
}
int main()
{
int array[10];
initialize<0,3,6>(array, 99);
std::cout << array[0] << " " << array[3] << " " << array[6] << std::endl;
}
Example: Click here
Just for the fun of it I created a somewhat different approach which needs a bit of infrastructure allowing initialization like so:
double array[40] = {};
"9 5 14"_idx(array) = 1;
"8 15 23 12"_idx(array) = 2;
If the digits need to be separated by commas, there is a small change needed. In any case, here is the complete code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
template <int Size, typename T = int>
class assign
{
int d_indices[Size];
int* d_end;
T* d_array;
void operator=(assign const&) = delete;
public:
assign(char const* base, std::size_t n)
: d_end(std::copy(std::istream_iterator<int>(
std::istringstream(std::string(base, n)) >> std::skipws),
std::istream_iterator<int>(), this->d_indices))
, d_array()
{
}
assign(assign<Size>* as, T* a)
: d_end(std::copy(as->begin(), as->end(), this->d_indices))
, d_array(a) {
}
assign(assign const& o)
: d_end(std::copy(o.begin(), o.end(), this->d_indices))
, d_array(o.d_array)
{
}
int const* begin() const { return this->d_indices; }
int const* end() const { return this->d_end; }
template <typename A>
assign<Size, A> operator()(A* array) {
return assign<Size, A>(this, array);
}
void operator=(T const& value) {
for (auto it(this->begin()), end(this->end()); it != end; ++it) {
d_array[*it] = value;
}
}
};
assign<30> operator""_idx(char const* base, std::size_t n)
{
return assign<30>(base, n);
}
int main()
{
double array[40] = {};
"1 3 5"_idx(array) = 17;
"4 18 7"_idx(array) = 19;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<double>(std::cout, " "));
std::cout << "\n";
}
I just had a play around for the sake of fun / experimentation (Note my concerns at the bottom of the answer):
It's used like this:
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
Source code:
#include <assert.h> //Needed to test variables
#include <iostream>
#include <cstddef>
template <class ArrayPtr, class Value>
class SmartAssign
{
ArrayPtr m_array;
public:
class Proxy
{
ArrayPtr m_array;
size_t m_index;
Proxy* m_prev;
Proxy(ArrayPtr array, size_t index)
: m_array(array)
, m_index(index)
, m_prev(nullptr)
{ }
Proxy(Proxy* prev, size_t index)
: m_array(prev->m_array)
, m_index(index)
, m_prev(prev)
{ }
void assign(Value value)
{
m_array[m_index] = value;
for (auto prev = m_prev; prev; prev = prev->m_prev) {
m_array[prev->m_index] = value;
}
}
public:
void operator=(Value value)
{
assign(value);
}
Proxy operator[](size_t index)
{
return Proxy{this, index};
}
friend class SmartAssign;
};
SmartAssign(ArrayPtr array)
: m_array(array)
{
}
Proxy operator[](size_t index)
{
return Proxy{m_array, index};
}
};
template <class T>
SmartAssign<T*, T> smartAssign(T* array)
{
return SmartAssign<T*, T>(array);
}
int main()
{
int array[10];
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
for (auto i : array) {
std::cout << i << "\n";
}
//Now to test the variables
assert(array[0] == 1 && array[8] == 1);
assert(array[1] == 2 && array[4] == 2 && array[2] == 2);
assert(array[3] == 3);
assert(array[5] == 4 && array[9] == 4 && array[6] == 4 && array[7] == 4);
}
Let me know what you think, I don't typically write much code like this, I'm sure someone will point out some problems somewhere ;)
I'm not a 100% certain of the lifetime of the proxy objects.
The best you can do if your indexes are unrelated is "chaining" the assignments:
array[9] = array[5] = array[14] = 1;
However if you have some way to compute your indexes in a deterministic way you could use a loop:
for (size_t i = 0; i < 3; ++i)
array[transform_into_index(i)] = 1;
This last example also obviously applies if you have some container where your indexes are stored. So you could well do something like this:
const std::vector<size_t> indexes = { 9, 5, 14 };
for (auto i: indexes)
array[i] = 1;
Compilers which still doesn't support variadic template argument and universal initialization list, it can be a pain to realize, that some of the posted solution will not work
As it seems, OP only intends to work with arrays of numbers, valarray with variable arguments can actually solve this problem quite easily.
#include <valarray>
#include <cstdarg>
#include <iostream>
#include <algorithm>
#include <iterator>
template <std::size_t size >
std::valarray<std::size_t> selection( ... )
{
va_list arguments;
std::valarray<std::size_t> sel(size);
//Skip the first element
va_start ( arguments, size );
va_arg ( arguments, int );
for(auto &elem : sel)
elem = va_arg ( arguments, int );
va_end ( arguments );
return sel;
}
int main ()
{
//Create an array of 30 integers
std::valarray<int> array(30);
//The first argument is the count of indexes
//followed by the indexes of the array to initialize
array[selection<3>(9,5,14)] = 1;
array[selection<4>(8,15,13, 12)] = 2;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
I remember, for static initialization exist syntax like:
int array[30] = {
[9] = 1, [8] = 2
}
And so on. This works in gcc, about another compilers - I do not know.
Use overload operator << .
#include <iostream>
#include <iomanip>
#include <cmath>
// value and indexes wrapper
template< typename T, std::size_t ... Ints> struct _s{ T value; };
//deduced value type
template< std::size_t ... Ints, typename T>
constexpr inline _s<T, Ints... > _ ( T const& v )noexcept { return {v}; }
// stored array reference
template< typename T, std::size_t N>
struct _ref
{
using array_ref = T (&)[N];
array_ref ref;
};
//join _s and _ref with << operator.
template<
template< typename , std::size_t ... > class IC,
typename U, std::size_t N, std::size_t ... indexes
>
constexpr _ref<U,N> operator << (_ref<U,N> r, IC<U, indexes...> ic ) noexcept
{
using list = bool[];
return ( (void)list{ false, ( (void)(r.ref[indexes] = ic.value), false) ... }) , r ;
//return r;
}
//helper function, for creating _ref<T,N> from array.
template< typename T, std::size_t N>
constexpr inline _ref<T,N> _i(T (&array)[N] ) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a) << _<0,3,4,5>(7) << _<8,9, 14>( 6 ) ;
for(auto x : a)std::cout << x << " " ;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
//result: 7 0 0 7 7 7 0 0 6 6 0 0 0 0 6
double b[101]{0};
_i(b) << _<0,10,20,30,40,50,60,70,80,90>(3.14)
<< _<11,21,22,23,24,25>(2.71)
<< _<5,15,25,45,95>(1.414) ;
}
struct _i_t
{
int * array;
struct s
{
int* array;
std::initializer_list<int> l;
s const& operator = (int value) const noexcept
{
for(auto i : l )
array[i] = value;
return *this;
}
};
s operator []( std::initializer_list<int> i ) const noexcept
{
return s{array, i};
}
};
template< std::size_t N>
constexpr _i_t _i( int(&array)[N]) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a)[{1,3,5,7,9}] = 7;
for(auto x : a)std::cout << x << ' ';
}
Any fancy trickery you do will be unrolled by the compiler/assembler into exactly what you have. Are you doing this for readability reasons? If your array is already init, you can do:
array[8] = array[15] = array[23] = array[12] = 2;
But I stress my point above; it will be transformed into exactly what you have.