How to have inheritance between template with union? - c++

I have the following two objects. Im wondering if there is a way to have Pixel as a base class of PixelBGR so that any operator (+,-,*,/, [], etc.) could be used without redefining them ?
template<class T, std::size_t N>
struct Pixel
{
T ch[N];
inline T& operator[](const int x)
{
return ch[x];
}
};
template<class T>
struct PixelBGR
{
union
{
struct
{
T b;
T g;
T r;
};
T ch[3];
};
inline T& operator[](const int x)
{
return ch[x];
}
};
EDIT: As suggested by πάντα ῥεῖ, here more details about what Im trying to do.
Im trying to have a generic class Pixel, which will be template to handle any type or size.
The usual are 1,2,3,4,8 or 16. The class with defines some operator such as +,-,*, etc.
Since most of the time, the Pixel<T,3> is a BGR pixel, I would like to define rapid access to r,g and b to avoid confusion, but still store it as BGR.
But the derived class should also provide the Operator which will be generic based on N.
EDIT2: By reading the comment of SergeyA, I forgot to say that the struct Pixel must not change size.
So I think balki answer is the best, by using member function. I was trying to make it with variables to avoid too much char ie: adding the (), but it seems to be too complicated for nothing. I still investigating CRTP, but I dont get it well, Im reading on that.

Answering the question as asked, this should give OP reuse of the operators without any undefined behavior:
#include <cstddef>
template<class T, std::size_t N>
struct Pixel
{
T ch[N];
inline T& operator[](const int x)
{
return ch[x];
}
Pixel& operator+= (const Pixel& ) { return *this;}
};
template<class T, std::size_t N>
Pixel<T, N> operator+ (const Pixel<T, N>& l, const Pixel<T, N>& r);
template<class T>
struct BgrPixel : Pixel<T, 3> {
using base = Pixel<T, 3>;
using base::base;
BgrPixel(const base& b) : base(b) { };
T& b = base::ch[0];
T& g = base::ch[1];
T& r = base::ch[2];
};
BgrPixel<int> a, b;
BgrPixel<int> c = a + b;
Alterinative would be to have b(), g() and r() as a member functions, but this would require you to access them as functions. You would also need const and non-const versions of them.
The benefits, however, would be that the size of the struct will not be increased and copy assignment would work naturally (which, in turn, could be solved by providing custom copy assignment).

The Curiously Recurring Template Pattern (CRTP) would work well in this case. In the CRTP the Derived class is used as a template argument to the Base class. Chapter 16.3 The Curiously Recurring Template Pattern (CRTP), from the C++ Templates - The Complete Guide, by David Vandevoorde and Nicolai M. Josuttis, explains things in more detail.
From the comments below, the usage of a union{struct{...}...} causes undefined behaviour (UB), but there have been some contradicting opinions upon this. As far as I'm aware, it is a gnu extension and supported by almost every compiler. glm for example uses union-structs quite very often.
As an alternative approach, you can use aliases (references) for the r,g,b variables.
#include <iostream>
template<typename T, std::size_t N, template<typename,std::size_t> class B >
struct Pixel
{
B<T,N> *crtp = static_cast<B<T,N>*>(this);
T& operator[](std::size_t x)
{
return crtp->ch[x];
}
Pixel& operator = (const Pixel &t)
{
crtp->ch[0] = t.crtp->ch[0];
crtp->ch[1] = t.crtp->ch[1];
crtp->ch[2] = t.crtp->ch[2];
return *crtp;
}
B<T,N> operator + (const B<T,N> &t)
{
B<T,N> tmp;
tmp[0] = crtp->ch[0] + t.crtp->ch[0];
tmp[1] = crtp->ch[1] + t.crtp->ch[1];
tmp[2] = crtp->ch[2] + t.crtp->ch[2];
return tmp;
}
B<T,N> operator - (const B<T,N> &t)
{
B<T,N> tmp;
tmp[0] = crtp->ch[0] - t.crtp->ch[0];
tmp[1] = crtp->ch[1] - t.crtp->ch[1];
tmp[2] = crtp->ch[2] - t.crtp->ch[2];
return tmp;
}
};
template<typename T, std::size_t N=3>
struct PixelBGR : Pixel<T, N, PixelBGR>
{
T ch[3];
T &r;
T &g;
T &b;
PixelBGR() : ch{},r(ch[0]),g(ch[1]),b(ch[2])
{}
PixelBGR& operator = (const PixelBGR &p)
{
ch[0] = p.ch[0];
ch[1] = p.ch[1];
ch[2] = p.ch[2];
return *this;
}
};
int main()
{
PixelBGR<int> p;
p.r = 25;
p.g = 14;
p.b = 58;
std::cout<< p[0] <<" , "<<p[1]<<" , "<<p[2] <<std::endl;
PixelBGR<int> q;
q = p;
std::cout<< q[0] <<" , "<<q[1]<<" , "<<q[2] <<std::endl;
PixelBGR<int> res1;
res1 = q + p;
std::cout<< res1.r <<" , "<<res1.g<<" , "<<res1.b <<std::endl;
PixelBGR<int> res2;
res2 = q - p;
std::cout<< res2.r <<" , "<<res2.g<<" , "<<res2.b <<std::endl;
}
Result:
25 , 14 , 58
25 , 14 , 58
50 , 28 , 116
0 , 0 , 0
Example using references: https://rextester.com/AZWG4319
Example using union-struct: https://rextester.com/EACC87146

First thanks to all of you for advise, and special thanks to #Constantinos Glynos, #balki and #SergeyA for the example they provide, those help me to achieve a solution that match my need.
I implemented the BGR and BGRA to show that the N works fine, now I just need to implement all the operator, and functions that I require.
Please feel free to edit, or tell me if there is something wrong with this.
Pixel.h
#include <cstdio> // std::size_t
#include <iostream> // std::cout
template<typename T, std::size_t N, template<typename, std::size_t> class B >
struct Pixel
{
T ch[N];
// ==============================================================
// Overload the accessor (so .ch[0] == direct access with [0].
T& operator[](std::size_t x){ return ch[x]; }
// ==============================================================
// Copy-assignement
Pixel& operator=( const Pixel &t )
{
for ( int i = 0; i < N; i++ )
ch[i] = t.ch[i];
return *this;
}
// ==============================================================
// Operator
B<T, N> operator+( const B<T, N> &t )
{
B<T, N> tmp;
for ( int i = 0; i < N; i++ )
tmp[i] = ch[i] + t.ch[i];
return tmp;
}
B<T, N> operator-( const B<T, N> &t )
{
B<T, N> tmp;
for ( int i = 0; i < N; i++ )
tmp[i] = ch[i] - t.ch[i];
return tmp;
}
template<typename T, std::size_t N, template<typename, std::size_t> class B >
friend std::ostream& operator<<( std::ostream& os, const Pixel &t );
};
// To print the vector
template<typename T, std::size_t N, template<typename, std::size_t> class B >
std::ostream& operator<<( std::ostream& os, const B<T, N> &t )
{
os << "Pixel: (" << t.ch[0];
for ( int i = 1; i < N; i++ )
os << ", " << t.ch[i];
os << ")";
return os;
}
template<typename T, std::size_t N = 3>
struct BGR : Pixel<T, N, BGR>
{
T& b() { return ch[0]; }
T& g() { return ch[1]; }
T& r() { return ch[2]; }
};
template<typename T, std::size_t N = 4>
struct BGRA : Pixel<T, N, BGRA>
{
T& b() { return ch[0]; }
T& g() { return ch[1]; }
T& r() { return ch[2]; }
T& a() { return ch[3]; }
};
Main.cpp
int main() {
std::cout << "Sizeof a float BGR: " << sizeof(BGR<float>) << std::endl;
std::cout << "Sizeof a float BGRA: " << sizeof(BGRA<float>) << std::endl;
BGR<int> p;
p.r() = 25;
p.g() = 14;
p.b() = 58;
std::cout << p << std::endl;
std::cout << p[0] << " , " << p[1] << " , " << p[2] << std::endl;
std::cout << p.b() << " , " << p.g() << " , " << p.r() << std::endl;
BGR<int> q;
q = p;
std::cout << q[0] << " , " << q[1] << " , " << q[2] << std::endl;
BGR<int> res1;
res1 = q + p;
std::cout << res1.r() << " , " << res1.g() << " , " << res1.b() << std::endl;
BGR<int> res2;
res2 = q - p;
std::cout << res2.r() << " , " << res2.g() << " , " << res2.b() << std::endl;
BGRA<float> a;
a.r() = 255.0f;
a.g() = 0.0f;
a.b() = 0.0f;
a.a() = 128.5f;
BGRA<float> b = a;
std::cout << a << std::endl;
return 0;
}

Related

How to apply overloaded operators of an underlying type to a wrapper type?

I have a wrapper struct around a container class
struct ContainerWrapper
{
Container data;
};
Container already has a bunch of overloaded operators defined, such as operator+, operator*, etc.
Is there a way to "inherit" all said operators without having to manually add them? In other words, can we avoid doing e.g.:
struct ContainerWrapper
{
auto operator+(const ContainerWrapper& other) const { return data + other.data; }
Container data;
};
and instead define some kind of implicit conversion between ContainerWrapper an Container such that one would be able to readily add two ContainerWrapper types together without having to do the above?
---- EDIT ----
I tried solving this with inheritance but it's giving me a type conversion problem.
Here is a following example code:
template <typename T, std::size_t N>
struct Container
{
Container operator+(const Container& other)
{
Container res;
for (std::size_t i = 0; i < N; ++i)
{
res.m_data[i] = m_data[i] + other.m_data[i];
}
return res;
}
T& operator[](std::size_t i) { return m_data[i]; }
const T& operator[](std::size_t i) const { return m_data[i]; }
private:
T m_data[N];
};
template <typename T, std::size_t N>
struct ContainerWrapper : public Container<T, N>
{
ContainerWrapper()
{
for (std::size_t i = 0; i < N; ++i)
{
this->operator[](i) = static_cast<T>(i);
}
}
};
int main()
{
using T = float;
Container<T, 3> cont1{};
cont1[0] = 1.f;
cont1[1] = 2.f;
cont1[2] = 3.f;
Container<T, 3> cont2{};
cont2[0] = 2.f;
cont2[1] = 3.f;
cont2[2] = 4.f;
const auto cont3 = cont1 + cont2;
std::cout << "cont1: " << cont1[0] << ", " << cont1[1] << ", " << cont1[2] << "\n";
std::cout << "cont2: " << cont2[0] << ", " << cont2[1] << ", " << cont2[2] << "\n";
std::cout << "cont3: " << cont3[0] << ", " << cont3[1] << ", " << cont3[2] << "\n";
ContainerWrapper<T, 3> contWrap1{};
ContainerWrapper<T, 3> contWrap2{};
const ContainerWrapper<T, 3> contWrap3 = contWrap1 + contWrap2; // I want this to return a ContainerWrapper<T, 3> type but it's giving a Container<T, 3> type instead
return 0;
}
The above does not compile because the type of contWrap3 is not a ContainerWrapper<T, 3>, but I want it to be.

Reading a WORD variable from a CArchive and casting to int at the same time

This might sound basic but:
WORD wSong = 0;
CArchive ar;
...
ar >> wSong;
m_sPublicTalkInfo.iSongStart = static_cast<int>(wSong);
At the moment I read the WORD into a specific variable and the cast it.
Can I read it in and cast at the same time?
Please note I can't serialize a int. It must be a WORD and cast to int.
Or
ar >> wSong;
m_sPublicTalkInfo.iSongStart = static_cast<int>(wSong);
I don't think there is a direct way. You could implement a helper function:
template <typename T, typename U>
T readAndCast (CArchive& ar) {
U x;
ar >> x;
return static_cast<T> (x);
}
m_sPublicTalkInfo.iSongStart = readAndCast<int, WORD>(ar);
It might be better to use the fixed-width integer types in your program, i.e. perhaps int_least16_t instead of int to be sure the type has the right size. WORD is fixed to 16bit, but int isn't. Also, WORD is unsigned and int isn't, so there could be an overflow during casting.
This is a example of how you could create a wrapper if you want the serialize syntax to remain consistent. It's designed to work with integrals and MFC unsigned types only.
#include <iostream>
#include <cstdint>
#include <sstream>
#include <type_traits>
// Fake the MFC types
using BYTE = std::uint8_t;
using WORD = std::uint16_t;
using DWORD = std::uint32_t;
using QWORD = std::uint64_t;
template<typename T>
struct is_valid_save_type : std::bool_constant<
std::is_same_v<BYTE, T> ||
std::is_same_v<WORD, T> ||
std::is_same_v<DWORD, T> ||
std::is_same_v<QWORD, T>
> {};
template<typename T>
struct is_valid_load_type : is_valid_save_type<T> {};
// Saves type T as a SaveType
template<typename T, typename SaveType>
struct save_as_type
{
explicit save_as_type(T value) : value(value) {}
explicit operator SaveType() const
{
return static_cast<SaveType>(value);
}
private:
T value;
// This class only works with integrals
static_assert(std::is_integral_v<T>);
// SaveType should be BYTE/WORD/DWORD/QWORD only
static_assert(is_valid_save_type<SaveType>::value);
};
// Loads type T as a LoadType
template<typename T, typename LoadType>
struct load_as_type
{
explicit load_as_type(T& value) : value_(value) {}
load_as_type& operator=(LoadType rhs)
{
value_ = rhs;
return *this;
}
private:
T& value_;
// T should be an integral
static_assert(std::is_integral_v<T>);
// T must be non-constant
static_assert(!std::is_const_v<T>);
// LoadType should be BYTE/WORD/DWORD/QWORD only
static_assert(is_valid_load_type<LoadType>::value);
};
class CArchive;
// Make the above types serializable
template<typename T, typename SaveType>
CArchive& operator<<(CArchive& ar, save_as_type<T, SaveType> const& s)
{
ar << static_cast<SaveType>(s);
}
template<typename T, typename LoadType>
CArchive& operator>>(CArchive& ar, load_as_type<T, LoadType> l)
{
LoadType t{};
ar >> t;
l = t;
}
// Use the following two functions in your code
template<typename SaveType, typename T>
save_as_type<T, SaveType> save_as(T const& t)
{
return save_as_type<T, SaveType>{ t };
}
template<typename LoadType, typename T>
load_as_type<T, LoadType> load_as(T& t)
{
return load_as_type<T, LoadType>{ t };
}
// Prevent loading into temporaries; i.e. load_as<BYTE>(11);
template<typename T, typename LoadType>
load_as_type<T, LoadType> load_as(const T&& t) = delete;
// Fake MFC Archive
class CArchive
{
public:
CArchive& operator<<(int i)
{
std::cout << "Saving " << i << " as an int\n";
return *this;
}
CArchive& operator<<(BYTE b)
{
std::cout << "Saving " << (int)b << " as a BYTE\n";
return *this;
}
CArchive& operator<<(WORD w)
{
std::cout << "Saving " << (int)w << " as a WORD\n";
return *this;
}
CArchive& operator<<(DWORD d)
{
std::cout << "Saving " << (int)d << " as a DWORD\n";
return *this;
}
CArchive& operator>>(int& i)
{
std::cout << "Loading as an int\n";
return *this;
}
CArchive& operator>>(BYTE& b)
{
std::cout << "Loading as a BYTE\n";
return *this;
}
CArchive& operator>>(WORD& w)
{
std::cout << "Loading as a WORD\n";
return *this;
}
CArchive& operator>>(DWORD& d)
{
std::cout << "Loading as a DWORD\n";
return *this;
}
};
int main()
{
CArchive ar;
int out_1 = 1;
int out_2 = 2;
int out_3 = 3;
int out_4 = 4;
ar << out_1 <<
save_as<BYTE>(out_2) <<
save_as<WORD>(out_3) <<
save_as<DWORD>(out_4);
std::cout << "\n";
int in_1 = 0;
int in_2 = 0;
int in_3 = 0;
int in_4 = 0;
ar >> in_1 >>
load_as<BYTE>(in_2) >>
load_as<WORD>(in_3) >>
load_as<DWORD>(in_4);
return 0;
}
Output:
Saving 1 as an int
Saving 2 as a BYTE
Saving 3 as a WORD
Saving 4 as a DWORD
Loading as an int
Loading as a BYTE
Loading as a WORD
Loading as a DWORD

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

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