extract an array from another array at compile time using c++ - 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)

Related

Can multiple parameter packs be expanded in a single expression?

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;
}

Print a struct with a known size

I have some structs that may contain some certain number of unsigned integer (They are either uint32_t or uint64_t). I want to print out the value of these struct in an understandable way.
For example I may have a struct like below.
struct test {
uint32_t ab = 0;
uint64_t cd = 1;
uint32_t ef = 2;
};
I think I could have a method pass the address of this struct and print it out by using the size of this struct. But not sure how to write the code.
As mentioned, C++11 has no reflection mechanism. The only way to obtain a list of members is to role out your own mechanism. Since you mentioned each member always has one of two types, it should be fairly straight forward. For instance, by creating a trait class.
template<class T>
struct mem_ptr {
// Tagged union type to generically refer to a member of a struct T
enum {u32, u64} alive;
union {
uint32_t T::* u32_ptr;
uint64_t T::* u64_ptr;
};
mem_ptr(uint32_t T::* u32_ptr) : alive(u32), u32_ptr(u32_ptr) {}
mem_ptr(uint64_t T::* u64_ptr) : alive(u64), u64_ptr(u64_ptr) {}
};
template<class> struct struct_members;
template<>
struct struct_members<test> {
mem_ptr<test> members[3] = {
&test::ab, &test::cd, &test::ef
};
};
template<class T>
auto operator<<(std::ostream& os, T const& str) -> decltype(struct_members<T>::members, os) {
struct_members<T> const mem;
char const *delim = "";
os << "{ ";
for(auto& m : mem.members) {
os << delim;
delim = ", ";
switch(m.alive) {
case m.u32: os << (str.*(m.u32_ptr)); break;
case m.u64: os << (str.*(m.u64_ptr)); break;
default: break;
}
}
os << " }";
return os;
}
Putting the above to the test (pun intended) on wandbox, prints:
{ 0, 1, 2 }
With that in-place, you can add support for a new structure by just defining the struct_members table for it:
struct test2 {
uint32_t ab1 = 5;
uint64_t cd2 = 3;
uint32_t ef3 = 8;
};
template<>
struct struct_members<test2> {
mem_ptr<test2> members[3] = {
&test2::ab1, &test2::cd2, &test2::ef3
};
};
And the stream operator previously written will work for it too.
If you need just a basic understanding about what is inside, you may reinterpret the structure as an array of uint32_t-s and print them in hex.
#include <iostream>
#include <iomanip>
struct test {
uint32_t ab = 0;
uint64_t cd = 1;
uint32_t ef = 2;
};
// For those who don't respect strict aliasing rules mentioned in comments
/*
template<class T>
void printStruct(const T& s)
{
auto* b = reinterpret_cast<const uint32_t*>(&s);
auto* e = b + sizeof(T)/sizeof(uint32_t);
std::cout << std::hex;
for (auto* i = b; i != e; ++i)
std::cout << std::setw(sizeof(uint32_t)*2) << std::setfill('0') << *i << ' ';
std::cout << std::dec;
}
*/
// For those who do respect strict aliasing rules mentioned in comments
template<class T>
void printStruct(const T& s)
{
const auto sc = sizeof(char);
const auto n = sizeof(uint32_t)/sc;
auto* b = reinterpret_cast<const unsigned char*>(&s);
auto* e = b + sizeof(T)/(sc*n);
std::cout << std::hex;
for (auto* i = b; i != e; i += n)
{
for (auto j = 0; j < n; ++j)
// For a big-endian machine n - 1 - j must be replaced by j
std::cout << std::setw(sc*2) << std::setfill('0') << *(i + n - 1 - j);
std::cout << ' ';
}
std::cout << std::dec;
}
int main()
{
printStruct(test());
return 0;
}
But the routine will print also alignment bytes and on a little-endian machine the two parts of an uint64_t will be reversed.
E.g. on my machine it prints
00000000 00000000 00000001 00000000 00000002 00007ffe
Where the first 00000000 is ab, the second 00000000 is alignment, 00000001 00000000 is cd, 00000002 is de and 00007ffe is alignment again.
One option would be to use std::tuple for your structures. e.g. your struct could be defined as:
typedef std::tuple< uint32_t, uint64_t, uint32_t > test;
You can then print any tuple using:
template<class Tuple, std::size_t N>
struct TuplePrinter {
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N - 1>::print(t);
std::cout << ", " << std::get<N - 1>(t);
}
};
template<class Tuple>
struct TuplePrinter<Tuple, 1> {
static void print(const Tuple& t)
{
std::cout << std::get<0>(t);
}
};
template<class... Args>
void print(const std::tuple<Args...>& t)
{
std::cout << "(";
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
std::cout << ")\n";
}
If you want to get back your named members you could derive a struct from your tuple, something like this:
struct test : public std::tuple< uint32_t, uint64_t, uint32_t >
{
typedef std::tuple< uint32_t, uint64_t, uint32_t > base;
test()
: base( 0, 1, 2 ),
ab( std::get< 0 >( *this ) ),
cd( std::get< 1 >( *this ) ),
ef( std::get< 2 >( *this ) )
{
}
uint32_t& ab;
uint64_t& cd;
uint32_t& ef;
};
or alternatively:
template<typename T>
void print(const T& t)
{
print(t.tuple);
}
struct test
{
uint32_t ab = 0;
uint64_t cd = 1;
uint32_t ef = 2;
typedef std::tuple< uint32_t&, uint64_t&, uint32_t& > tuple_t;
const tuple_t tuple = { ab, cd, ef };
};
or (as suggested by #Jarod42):
void print(const test& t)
{
print(std::tie(t.ab, t.cd, t.ef));
}

Can I give different behaviours to boost::proto::tag types?

I am trying to use boost proto to lazily evaluate expressions, what I want to do is be able to give different behaviours to tags like +, -, function etc.
function(
terminal(8functionILi2EE)
, plus(
multiplies(
terminal(6tensorILi0EE)
, terminal(6tensorILi1EE)
)
, multiplies(
terminal(6tensorILi2EE)
, terminal(6tensorILi3EE)
)
)
)
For a tree like above, I want to be able to specify how each of the tree nodes should behave.
For eg.
struct context : proto::callable_context< context const >
{
// Values to replace the tensors
std::vector<double> args;
// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;
// Handle the tensors:
template<int I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}
template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
};
When I do
double result = (_tensorA + _tensorB)(10, 20);
I expect my output to be
10
+
20
But it's just
10
20
Any help would be deeply appreciated! :)
template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
The template argument I is non-deducible, so the overload will never be applicable. Drop the template argument:
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
HOWEVER What you really want is intercept the binary operator. Well. Note it's binary. So it has two args:
template<size_t I, size_t J>
void operator()(proto::tag::plus, proto::literal<tensor<I>>&, proto::literal<tensor<J>>&) const {
std::cout << " + " << std::endl;
}
Live On Coliru
However, this blocks further evaluation of the expression tree. Not what you wanted, right. So, let's do a simplisitic re-implementation:
template<size_t I, size_t J>
double operator()(proto::tag::plus, proto::literal<tensor<I>>& a, proto::literal<tensor<J>>& b) const {
auto va = (*this)(proto::tag::terminal{}, a.get());
std::cout << " + " << std::endl;
auto vb = (*this)(proto::tag::terminal{}, b.get());
return va + vb;
}
Live On Coliru
Generic, please
However, something tells me you wanted generic expressions. So t1 + (t2 + t3) should also work, but (t2 + t3) is no literal...
Let's simplify by delegating:
template<typename A, typename B>
double operator()(proto::tag::plus, A& a, A& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}
Full Sample
Live On Coliru
#include <boost/proto/proto.hpp>
#include <vector>
namespace proto = boost::proto;
template <size_t N> struct tensor { };
template <size_t N, size_t M> tensor<N+M> operator+(tensor<N>, tensor<M>) { return {}; }
struct context : proto::callable_context< context const >
{
using base_type = proto::callable_context<context const>;
// Values to replace the tensors
std::vector<double> args { 0, 111, 222, 333 };
// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;
// Handle the tensors:
template<size_t I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}
template<typename A, typename B>
double operator()(proto::tag::plus, A& a, B& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}
};
int main() {
proto::literal<tensor<1> > t1;
proto::literal<tensor<2> > t2;
proto::literal<tensor<3> > t3;
auto r = proto::eval(t1 + (t2 + t3), context());
std::cout << "eval(t1 + (t2 + t3)) = " << r << "\n";
}
Prints
111
+
222
+
333
eval(t1 + (t2 + t3)) = 666

Lookup table with constexpr

I'm looking to create a lookup table of coordinates, something like:
int a[n][2] = {{0,1},{2,3}, ... }
For a given n, to be created at compile time. I started looking into constexpr, but is seems like a function returning a constexpr std::vector<std::array <int, 2> > isn't an option, as I get:
invalid return type 'std::vector<std::array<int, 2ul> >' of constexpr function
How can create such a compile time array?
With C++14, you do not need too much template magic. Here an example of how to have a lookup table for f(x) = x^3 with the first coordinate being the x value and the second coordinate being the f(x) value:
#include <iostream>
template<int N>
struct Table
{
constexpr Table() : values()
{
for (auto i = 0; i < N; ++i)
{
values[i][0] = i;
values[i][1] = i * i * i;
}
}
int values[N][2];
};
int main() {
constexpr auto a = Table<1000>();
for (auto x : a.values)
std::cout << "f(" << x[0] << ") = " << x[1] << '\n';
}
I'll dump the code first, adding references and comments where necessary/appropriate later. Just leave a comment if the result is somewhat close to what you're looking for.
Indices trick for pack expansion (required here to apply the generator), by Xeo, from this answer, modified to use std::size_t instead of unsigned.
#include <cstddef>
// by Xeo, from https://stackoverflow.com/a/13294458/420683
template<std::size_t... Is> struct seq{};
template<std::size_t N, std::size_t... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<std::size_t... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
Generator function:
#include <array>
template<class Generator, std::size_t... Is>
constexpr auto generate_array_helper(Generator g, seq<Is...>)
-> std::array<decltype(g(std::size_t{}, sizeof...(Is))), sizeof...(Is)>
{
return {{g(Is, sizeof...(Is))...}};
}
template<std::size_t tcount, class Generator>
constexpr auto generate_array(Generator g)
-> decltype( generate_array_helper(g, gen_seq<tcount>{}) )
{
return generate_array_helper(g, gen_seq<tcount>{});
}
Usage example:
// some literal type
struct point
{
float x;
float y;
};
// output support for `std::ostream`
#include <iostream>
std::ostream& operator<<(std::ostream& o, point const& p)
{ return o << p.x << ", " << p.y; }
// a user-defined generator
constexpr point my_generator(std::size_t curr, std::size_t total)
{
return {curr*40.0f/(total-1), curr*20.0f/(total-1)};
}
int main()
{
constexpr auto first_array = generate_array<5>(my_generator);
constexpr auto second_array = generate_array<10>(my_generator);
std::cout << "first array: \n";
for(auto p : first_array)
{
std::cout << p << '\n';
}
std::cout << "========================\n";
std::cout << "second array: \n";
for(auto p : second_array)
{
std::cout << p << '\n';
}
}
What about using GNU gperf or some other code generation utility?

Slicing std::array

Is there an easy way to get a slice of an array in C++?
I.e., I've got
array<double, 10> arr10;
and want to get array consisting of five first elements of arr10:
array<double, 5> arr5 = arr10.???
(other than populating it by iterating through first array)
The constructors for std::array are implicitly defined so you can't initialize it with a another container or a range from iterators. The closest you can get is to create a helper function that takes care of the copying during construction. This allows for single phase initialization which is what I believe you're trying to achieve.
template<class X, class Y>
X CopyArray(const Y& src, const size_t size)
{
X dst;
std::copy(src.begin(), src.begin() + size, dst.begin());
return dst;
}
std::array<int, 5> arr5 = CopyArray<decltype(arr5)>(arr10, 5);
You can also use something like std::copy or iterate through the copy yourself.
std::copy(arr10.begin(), arr10.begin() + 5, arr5.begin());
Sure. Wrote this:
template<int...> struct seq {};
template<typename seq> struct seq_len;
template<int s0,int...s>
struct seq_len<seq<s0,s...>>:
std::integral_constant<std::size_t,seq_len<seq<s...>>::value> {};
template<>
struct seq_len<seq<>>:std::integral_constant<std::size_t,0> {};
template<int Min, int Max, int... s>
struct make_seq: make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s>
struct make_seq<Min, Min, s...> {
typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min,Max>::type;
template<std::size_t src, typename T, int... indexes>
std::array<T, sizeof...(indexes)> get_elements( seq<indexes...>, std::array<T, src > const& inp ) {
return { inp[indexes]... };
}
template<int len, typename T, std::size_t src>
auto first_elements( std::array<T, src > const& inp )
-> decltype( get_elements( MakeSeq<len>{}, inp ) )
{
return get_elements( MakeSeq<len>{}, inp );
}
Where the compile time indexes... does the remapping, and MakeSeq makes a seq from 0 to n-1.
Live example.
This supports both an arbitrary set of indexes (via get_elements) and the first n (via first_elements).
Use:
std::array< int, 10 > arr = {0,1,2,3,4,5,6,7,8,9};
std::array< int, 6 > slice = get_elements(arr, seq<2,0,7,3,1,0>() );
std::array< int, 5 > start = first_elements<5>(arr);
which avoids all loops, either explicit or implicit.
2018 update, if all you need is first_elements:
Less boilerplaty solution using C++14 (building up on Yakk's pre-14 answer and stealing from "unpacking" a tuple to call a matching function pointer)
template < std::size_t src, typename T, int... I >
std::array< T, sizeof...(I) > get_elements(std::index_sequence< I... >, std::array< T, src > const& inp)
{
return { inp[I]... };
}
template < int N, typename T, std::size_t src >
auto first_elements(std::array<T, src > const& inp)
-> decltype(get_elements(std::make_index_sequence<N>{}, inp))
{
return get_elements(std::make_index_sequence<N>{}, inp);
}
Still cannot explain why this works, but it does (for me on Visual Studio 2017).
This answer might be late... but I was just toying around with slices - so here is my little home brew of std::array slices.
Of course, this comes with a few restrictions and is not ultimately general:
The source array from which a slice is taken must not go out of scope. We store a reference to the source.
I was looking for constant array slices first and did not try to expand this code to both const and non const slices.
But one nice feature of the code below is, that you can take slices of slices...
// ParCompDevConsole.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include "pch.h"
#include <cstdint>
#include <iostream>
#include <array>
#include <stdexcept>
#include <sstream>
#include <functional>
template <class A>
class ArraySliceC
{
public:
using Array_t = A;
using value_type = typename A::value_type;
using const_iterator = typename A::const_iterator;
ArraySliceC(const Array_t & source, size_t ifirst, size_t length)
: m_ifirst{ ifirst }
, m_length{ length }
, m_source{ source }
{
if (source.size() < (ifirst + length))
{
std::ostringstream os;
os << "ArraySliceC::ArraySliceC(<source>,"
<< ifirst << "," << length
<< "): out of bounds. (ifirst + length >= <source>.size())";
throw std::invalid_argument( os.str() );
}
}
size_t size() const
{
return m_length;
}
const value_type& at( size_t index ) const
{
return m_source.at( m_ifirst + index );
}
const value_type& operator[]( size_t index ) const
{
return m_source[m_ifirst + index];
}
const_iterator cbegin() const
{
return m_source.cbegin() + m_ifirst;
}
const_iterator cend() const
{
return m_source.cbegin() + m_ifirst + m_length;
}
private:
size_t m_ifirst;
size_t m_length;
const Array_t& m_source;
};
template <class T, size_t SZ>
std::ostream& operator<<( std::ostream& os, const std::array<T,SZ>& arr )
{
if (arr.size() == 0)
{
os << "[||]";
}
else
{
os << "[| " << arr.at( 0 );
for (auto it = arr.cbegin() + 1; it != arr.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
std::ostream& operator<<( std::ostream& os, const ArraySliceC<A> & slice )
{
if (slice.size() == 0)
{
os << "^[||]";
}
else
{
os << "^[| " << slice.at( 0 );
for (auto it = slice.cbegin() + 1; it != slice.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
A unfoldArray( std::function< typename A::value_type( size_t )> producer )
{
A result;
for (size_t i = 0; i < result.size(); i++)
{
result[i] = producer( i );
}
return result;
}
int main()
{
using A = std::array<float, 10>;
auto idf = []( size_t i ) -> float { return static_cast<float>(i); };
const auto values = unfoldArray<A>(idf);
std::cout << "values = " << values << std::endl;
// zero copy slice of values array.
auto sl0 = ArraySliceC( values, 2, 4 );
std::cout << "sl0 = " << sl0 << std::endl;
// zero copy slice of the sl0 (the slice of values array)
auto sl01 = ArraySliceC( sl0, 1, 2 );
std::cout << "sl01 = " << sl01 << std::endl;
return 0;
}