Array compile-time generated? - c++

In this answer (it is not strictly necessary to read the whole question + answer) some code produces a compile-time array like:
template<unsigned...Is,class Tuple>
unsigned index_of(indexes<Is...>,void const* p, Tuple const&t){
void const* r[]={ nullptr, &std::get<Is>(t)... }; // <-- this is the array I'm referring to
auto it = std::find( std::begin(r), std::end(r), p );
if (it==std::end(r))
return -1;
else
return (it-std::begin(r))-1;
}
My question is: is that array entirely compile-time generated with the addresses of each element of a tuple? Is that the compile-time advantage? Or is the array runtime-generated (in that case, where's the compile-time advantage at all?)
Rephrased: why is the complex templated code here necessary at all instead of a simple runtime function which iterates with a for loop over all the elements of the tuple and compares the pointers? What's the gain in all that?? Something regarding the array creation? I don't really see it and I can't believe all that work was done for nothing or just to brag around "I can mess stuff up with templates, take a look"

No, since the tuple address is not known at compile-time. The only thing thats known at compile time is the size of the array, since its extracted from the size of the tuple (Via pack expansion).
Thats a weird algorithm thats only doing type erasure via void* to be able to store tuple elements on an array and then do something on them via standard algorithms.
This has much more sense (Indices trick ommitted to be more clear):
template<typename Tuple , typename T>
bool find_in_tuple( const Tuple& t , const T& e )
{
bool result[] = { (std::get<Indices>( t ) == e)... };
return std::any_of(std::begin(result) , std::end(result) , [](bool b){ return b; } );
}
Here is a running example.
For the index_of feature, you can add a counter to the closure when doing any_of(), or do something more complicated like this:
template<typename Tuple , typename T>
std::index_of index_of( const Tuple& t , const T& e )
{
std::size_t index = 0;
std::tuple<bool,std::size_t> result[] = { std::make_tuple(Indices,std::get<Indices>( t ) == e)... };
bool exists = std::any_of(std::begin(result) , std::end(result) , [&](const std::pair<std::size_t,bool>& p){ index = p.first; return p.second; } );
if(exists)
return index;
else
throw std::bad_argument{};
}

Related

Iterating over container or range - problem with constness

I am trying to write a template function that will sum up all elements of some collection - specified either as a plain stl container, or as a ranges-v3's range. (The actual function, as shown below is a bit more generic) I thought this would work:
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(range.begin());
Ret sum = zero;
int numElements = 0;
for (It it = range.begin(); it != range.end(); ++it) {
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
This indeed works for STL elements, but not for ranges. This gives me a very long error:
<this file, at line 'using It'> error C2662: 'ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>>,ranges::v3::iter_transform_view<Rng,ranges::v3::indirected<Fun>>::adaptor<false>>>,ranges::v3::remove_if_view<ranges::v3::transform_view<Rng,Fun>,ranges::v3::logical_negate_<EnemyGroup::stepUpdate::<lambda_c582fb1297dce111c4572cef649d86b9>>>::adaptor>> ranges::v3::view_facade<Derived,ranges::v3::finite>::begin<Derived,false,0x0>(void)': cannot convert 'this' pointer from 'const Range' to 'ranges::v3::view_facade<Derived,ranges::v3::finite> &'
note: Conversion loses qualifiers
originally, I thought it was some deficiency of the vs2015 branch of ranges-v3. Without thinking much, I just hacked a quick walkaround:
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(const_cast<Range*>(&range)->begin());
Ret sum = zero;
int numElements = 0;
for (It it = const_cast<Range*>(&range)->begin(); it != const_cast<Range*>(&range)->end(); ++it) {
//sum += extract(std::as_const(*it)); (does not work either, converts to void)
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
but with the newest MSVC version that just came out from preview, the master branch of ranges is now officially supported. Yet, the above error prevails.
Is using range's objects as const& a wrong thing to do? I know these objects are lightweight and are easy to copy around, but using a const reference shouldn't hurt, or? On the other hand, if a concrete STL container is passed, I need it to be passed as const&
If using const& is incorrect, is there some easy way to have a function work with both containers and ranges, without writing anything at the call site (e.g. invoking view::all)
I am using Visual Studio Community 2017, Version 15.9.3. Note, that before 15.9, range-v3 in its master branch was not supported.
Since you are asking how exactly I call it. My actual code is complicated, but I reduced it down to this small example:
#include <set>
#include <range/v3/view/filter.hpp>
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(range.begin());
Ret sum = zero;
int numElements = 0;
for (It it = range.begin(); it != range.end(); ++it) {
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
int main() {
std::set<int*> units;
auto [vsum, num] = sum(
units | ranges::v3::view::filter([](const int* eu) { return *eu>0; }),
0,
[](const int* eu) { return *eu/2; }
);
}
This gives me the same conversion errors as above.
Not all ranges are const-iterable. That is, there are range types T for which const T is not a range. filter is the classic example: it needs to cache the value of the iterator returned from begin so that future calls are O(1) (See http://eel.is/c++draft/range.filter.view#6). Consequently, begin cannot be a const member function without violating the Standard Library policy that const members are callable from multiple threads without introducing data races.
As a consequence, const Range& isn't idiomatic for accepting general Range arguments as it was for accepting "container that I don't intend to modify." We recommend that functions that take Range arguments accept them by forwarding reference. If you alter your program to:
#include <set>
#include <range/v3/view/filter.hpp>
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(Range&& range, Ret zero, Func extract) { // Note "Range&&"
Ret sum = zero;
int numElements = 0;
for (auto&& e : range) {
sum += extract(e);
++numElements;
}
return { sum, numElements };
}
int main() {
std::set<int*> units;
auto [vsum, num] = sum(
units | ranges::v3::view::filter([](const int* eu) { return *eu>0; }),
0,
[](const int* eu) { return *eu/2; }
);
}
It will compile and run correctly.

Better understanding of 3D to 1D array conversion in C++

I'm working on a school project in which I need to dynamically manage a 3D matrix (or array, I don't think it makes a difference, right?).
My first idea was to use a C-like approach, like this:
3Dmatrix(unsigned int height, unsigned int col, unsigned int row) : _3D_matrix(0), _row(0), _col(0), _height(0) {
try {
_3D_matrix = new T**[height];
for(int i =0; i<height; i++){
_3D_matrix[i] = new T*[col];
for(int j =0; j<col; j++){
_3D_matrix[i][j] = new T[row];
}
}
}
catch(...) {
delete[] _3D_matrix;
throw;
}
_row = row;
_col = col;
_height = height;
}
With this approach, though, the memory is not contiguous, and trying to work with iterators is almost impossible. So I decided to switch to a different strategy, "indexing" the 3D array to a 1D array using the formula
A[ x * height * depth + y * depth + z] 
to index the element M[x][y][z]. Since I'm not really sure this approach is what I'm looking for, and I also find other discussions on this topic not very helpful, do you think this approach can serve my purpose?
In particular, I'm worried about getter and setter methods, as well as iterators for reading and writing.
PS: since this project is for didactic use, I'm not allowed to use std library classes like vector or similar, and C++11 or later as well
You could try an approach like this:
struct Vector {
unsigned int X;
unsigned int Y;
unsigned int Z;
};
struct Matrix {
Vector rows[3]; // Depends on if you want row or col major.
// Vector cols[3];
};
// Or Matrix {
Vector* pRows; // Depends on if you want row or col major.
// Vector* pCols;
// Or
struct Matrix { // Row Major
Vector row1;
Vector row2;
Vector row3;
};
// Or
struct Matrix { // Col Major
Vector col1;
Vector col2;
Vector col3;
};
I did not add any constructors, operators nor functions only just shown basic data structure to illustrate the main point.
Note: This kind of pattern has a fixed dimensional size as it is a 3x3x3 matrix.
I do have a class template that can be a variable size matrix of any number of dimensions however it does use advanced techniques in which you stated that you were not able to use such as the standard library and c++11 or higher features. However as a bonus and for future use I can show it here as a good reference to look back on. This does not have anything to do with actually answering your question above; but this is what modern c++ would look like.
file Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
#include <algorithm>
#include <numeric>
namespace foo {
template<typename Type, size_t... Dims>
class Matrix {
public:
static const size_t _numDims = sizeof...(Dims);
private:
size_t _numElements;
std::vector<Type> _elements;
std::vector<size_t> _strides;
public:
Matrix() noexcept;
template<typename... Args>
Matrix( Args&&... args ) noexcept;
const Type& operator[]( size_t idx );
const Type operator[]( size_t idx ) const;
const Type& operator() ( size_t idx );
const Type operator() ( size_t idx ) const;
size_t numElements() const {
return _elements.size();
}
const std::vector<size_t>& strides() const {
return _strides;
}
const std::vector<Type>& elements() const {
return _elements;
}
};
#include "Matrix.inl"
} // namespace foo
#endif // !MATRIX_H
file Matrix.inl
template<typename Type, size_t... Dims>
Matrix<Type, Dims...>::Matrix() noexcept :
_strides( { Dims... } ) {
using std::begin;
using std::end;
auto mult = std::accumulate( begin( _strides ), end( strides ), 1, std::multiplies<>() );
_numElements = mult;
_elements.resize( _numElements );
}
template<typename Type, size_t... Dims>
template<typename... Args>
Matrix<Type, Dims...>::Matrix( Args&&... args ) noexcept :
_elements( { args... } ),
_strides( { Dims... } ) {
_numElements = _elements.size();
}
template<typename Type, size_t... Dims>
const Type Matrix<Type, Dims...>::operator[]( size_t idx ) const {
return _elements[idx];
}
template<typename Type, size_t... Dims>
const Type& Matrix<Type, Dims...>::operator[]( size_t idx ) {
return _elements[idx];
}
template<typename Type, size_t... Dims>
const Type Matrix<Type, Dims...>::operator()( size_t idx ) const {
return _elements[idx];
}
template<typename Type, size_t... Dims>
const Type& Matrix<Type, Dims...>::operator()( size_t idx ) {
return _elements[idx];
}
typical uses:
{
Matrix<int,2,3,4> iMat2x3x4;
Matrix<double,5,9> dMat5x9;
struct MyStruct {
int x;
float y;
char z;
};
Matrix<MyStruct, 4, 9, 7, 2, 3, 6> massiveMyStructMatrix;
}
The class upon instantiation will store the elements into one of its member vectors while calculating the strides for the dimensions and storing them into another vector. If a matrix is a 2x3x4x5 which is a 4D matrix the _strides container will have 4 values {2,3,4,5} respectively. This way if you need to do any kind of indexing the values are stored sequentially and you don't have to remember them, you can just index into the vector to get the size of the stride to do the appropriate indexing in the current level of your loop. All of the elements are contiguous in memory via the vector. There are also a few basic operators [] and () for both non const and const types. A method to return the number of elements which is the size of the _elements container. And two methods to return the actual containers.
Now you could take this idea and abstract the vectors out of the way however it still does not remove the dependency of the c++11 and higher features especially the use of variadic templates. This is nothing more than a good reference for future use.
With this approach, though, the memory is not contiguous ...
That's not wholly true. Each row is contiguous, and if you mostly operate row-by-row, that might be fine. It's a performance question anyway, so get it working as simply as possible first and worry about optimization later (if at all).
[indexing] ... I'm not really sure this approach is what I'm looking for ... do you think this approach can serve my purpose?
What is your purpose?
A flattened array is easier to manage in the sense that there's only one dynamic (de)allocation - your existing nested structure is buggy because it's hard to clean up correctly part-way through construction.
A flattened array is probably slightly faster, if you care, depending on size and access pattern.
A nested structure is easier to write (and test, and generalize) in that you can layer it up one dimension at a time, roughly like
template <typename T> class Vector;
template <typename T> using Matrix2d = Vector<Vector<T>>;
template <typename T> using Matrix3d = Vector<Matrix2d<T>>;
trying to work with iterators is almost impossible
Slow down. Write one layer of abstraction at a time. If you can write the get(x,y,z) accessor, do that first and layer iteration on top of it.

Multidimensional arrays represented as 1D (templatised for n dimensions)

Declaring multidimensional arrays with static size is quite easy in C++ and the array then is stored in one continuous block of memory (row major layout).
Problem
However declaring dynamically allocated multidimensional arrays (size known only at runtime) in C++ is quite tricky as discussed in other SO thread regarding arrays. To preserve the same syntax with multiple square brackets (in case of 2D array) you need to create an array of pointers, which point to another set of arrays (rows). With more dimensions it adds more (unnecessary) levels of indirection, memory fragmentation, and with small sizes of the array the pointers can take more memory than then the actual data.
One of the solutions is to use 1D array and then recalculate the indices.
Example:
3D array with sizes 10, 3 and 5. I want an element at positions 3, 1, 4 instead of writing 3darray[3][1][4] I would write 3darray[index], where index would be calculated as 3*(y_dym_size*z_dym_size) + 1*(z_dym_size) + 4 which, when substituted, results to 3*(3*5)+1*(5)+4.
I can easily make a class that encapsulates a dynamically allocated array and recomputes in indices in the presented manner, but this is not practical, as it needs to be written for every number of dimensions.
Question:
I would like to create a template that would work for arbitrary number of dimensions with zero overhead (which is the spirit of modern C++ - having reusable code/classes where more work is being shifted to the compiler). I have the following code that works for n-dimensional array, however does not have 0 overhead. It contains for loop and also have an array which is being used in the 1D resolution:
template <class T, size_t DIM>
class arrayND{
std::array<size_t, DIM> sizes;
std::array<size_t, DIM-1> access_multiplier;
vector<T> data;
public:
using iterator = typename vector<T>::iterator;
using const_iterator = typename vector<T>::const_iterator;
template <typename... Args, typename std::enable_if_t<sizeof...(Args) == DIM, int> = 0>
arrayND(Args&&... args) {
std::array<size_t, DIM> temp{args...};
sizes = temp;
size_t mult = 1;
for(int i = DIM-2; i >= 0; --i){
mult *= sizes[i+1];
access_multiplier[i] = mult;
}
data.resize(mult*temp[0]);
}
template <typename... Args, typename std::enable_if_t<sizeof...(Args) == DIM, int> = 0>
T& get(Args&&... args){
std::array<size_t, DIM> idx_copy{args...};
size_t index = idx_copy[DIM-1];
for(int i = DIM-2; i >= 0; --i){
index += idx_copy[i]*access_multiplier[i];
}
return data[index];
}
template <typename... Args, typename std::enable_if_t<sizeof...(Args) == DIM, int> = 0>
T& operator()(Args&&... args){
return get(args...);
}
void set(const T& elem){
fill(begin(data), end(data), elem);
}
iterator begin(){
return begin(data);
}
iterator end(){
return end(data);
}
const_iterator begin() const{
return cbegin(data);
}
const_iterator end() const{
return cend(data);
}
};
Other approach I was thinking of was to utilise variadic templates, which would be hopefully - after compiler optimization - identical to code written specially for some number of dimensions:
int getIndex(size_t index){
return index;
}
template<typename... Args>
int getIndex(size_t index, Args... args){
return access_multiplier[DIM-sizeof...(Args)-1]*index + getIndex(args...);
}
template <typename... Args, typename std::enable_if_t<sizeof...(Args) == DIM, int> = 0>
T& get(Args&&... args){
return data[getIndex(args...)];
/*std::array<size_t, DIM> idx_copy{args...};
size_t index = idx_copy[DIM-1];
for(int i = DIM-2; i >= 0; --i){
index += idx_copy[i]*access_multiplier[i];
}
return data[index];*/
}
Is there a way in the current version (C++17) or the C++ language how to obtain both flexibility (arbitrary number of dimensions) and performance (zero overhead compares to code written specially for some number of dimensions)? If there has to be overhead then it makes more sense to hardcode it for lets say up to 5 dimensions.
Is there already an implementation of dynamics multidimensional array in some existing library?
Split the view from the storage.
An n-dimensional array view of T is a class with a pointer to T and some way of getting n-1 stride sizes. [] returns an n-1 dimensional array view.
There are two different flavours of such views. The first stores the strides, the second a pointer to a contiguous buffer of strides. Both have their advantages; the first with care can even optimize when some or all dimensions are fixed. But I'll do the 2nd.
template<class T, std::size_t N>
struct slice {
T* ptr=0;
std::size_t const* strides=0;
slice<T,N-1> operator[]( std::size_t i )const{
return { ptr + i**strides, strides+1 };
}
};
template<class T>
struct slice<T,1> {
T* ptr=0;
std::size_t const* strides=0;
T& operator[]( std::size_t i )const{
return *(ptr + i**strides);
}
};
this one permits per-element strides.
Now you just have to expose a stride<T,N> to do chained [] on. This is similar to how I'd write it for 3 dimensions.
If you prefer (x,y,z) syntax and your only problem is the for loop and are afraid the compiler did not flatten it, you can write it force flattened using pack expansion. But profile and examine optimized assembly first.

Const converting std containers

Consider that I have a std::vector.
std::vector<int> blah;
blah.push_back(1);
blah.push_back(2);
I now want to pass the vector somewhere and disallow modifying the contents of the objects its contains while still allowing to modify the container when able:
// Acceptable use:
void call_something() {
std::vector<int> blah;
blah.push_back(1);
blah.push_back(2);
// Currently, compiler error because of mismatching types
something(blah);
}
void something(std::vector<const int>& blah)
{
// Auto translates to 'const int'
for ( auto& i : blah ) {
// User cannot modify i.
std::cout << i << std::endl;
}
blah.push_back(blah.size()); // This should be acceptable
blah.emplace_back(); // This should be acceptable
return;
}
// Unacceptable use:
void something_else(const std::vector<int>& blah)
{
// Because of const vector, auto translates to 'const int'
for ( auto& i : blah ) {
std::cout << i std::endl;
}
blah.push_back(blah.size()); // This will present an unacceptable compiler error.
blah.emplace_back(); // This will present an unacceptable compiler error.
return;
}
Is there an easy way to do this?
To enable the operations you wish to allow while preventing the others, you need to take a fine-grained approach to your function's interface. For example, if your calling code were to pass const iterators (begin and end) as well as a back inserter (or custom back emplacer functor), then exactly the subset of operations you showed would be possible.
template <class Iter, class F>
void something(Iter begin, Iter end, F&& append)
{
using value_type = typename std::iterator_traits<Iter>::value_type;
std::copy(begin, end, std::ostream_iterator<value_type>(std::cout, "\n"));
append(std::distance(begin, end));
append();
return;
}
That said I don't find your examples particularly compelling. Do you have a real scenario in which you must maintain mutable elements, pass a mutable container to a function, yet treat the passed elements as immutable?
There is no easy way to do this. One way would be to wrap a vector in a type that exposes only the functionality that you want to allow. For instance
template<typename T, typename A = std::allocator<T>>
struct vector_wrap
{
using iterator = typename std::vector<T, A>::const_iterator;
using const_iterator = typename std::vector<T, A>::const_iterator;
using size_type = typename std::vector<T, A>::size_type;
vector_wrap(std::vector<T, A>& vec)
: vec_(&vec)
{}
void push_back(T const& value) { vec_->push_back(value); }
void push_back(T&& value) { vec_->push_back(std::move(value)); }
size_type size() { return vec_->size(); }
iterator begin() const { return vec_->cbegin(); }
iterator end() const { return vec_->cend(); }
private:
std::vector<T, A> *vec_;
};
Since the above implementation only stores a pointer to the vector it wraps, you'll have to ensure that the lifetime of the vector is longer than that of vector_wrap.
You'll have to modify something and something_else so that they take a vector_wrap<int> as argument. Since vector_wrap::begin and vector_wrap::end return const_iterators, you'll not be allowed to modify existing elements within the for statement.
Live demo

How to return boost::fusion::vector<x,y,z> elements to add to a std::array<boost::fusion::vector<x,y,z>>?

I have a std::array and a boost::fusion::vector<X, Y> which I want to pass in to func1(). This function will add a boost::fusion::vector<X, Y> instance to each std::array element.
I have to use fusion::fold() so that I can add the correct number of elements to the fusion::vector<X,Y>, right?
So I currently have something like this:
void func1(){
boost::fusion::vector<X,Y> my_vec;
std::array<boost::fusion::vector<X,Y> > my_array[10];
func2(my_vec, my_array);
}
void func2(boost::fusion::vector<X,Y> my_vec, std::array<boost::fusion::vector<X,Y> > my_array){
//THIS IS THE PART I AM UNSURE ABOUT
for(int k=0; k<10; k++){
//The first two parameters aren't so important- just included to show the idea
my_array[k] = boost::fusion::fold(my_vec, 1, some_struct);
}
}
//This part is irrelevant
struct some_struct
{
typedef int result_type;
template<typename T>
int operator()(int x, T& t) const
{
t = something(x);
//Not sure if this part needs to return a boost::fusion::vector<X, Y>
return x;
}
};
The part I am unsure about is how to use the signature of my_vec in order to create multiple boost::fusion::vector<X,Y> instances and return them back so that I can add to the array in func2().
Could somebody please advise?
EDIT - Just spotted I got the first parameter for fold() wrong, have amended my question.
I'm not sure I understood your question really well so first let's explain what fold is to try to clarify.
In general (not just for fusion) "folding" a function taking two parameters is applying it to each and every element of the vector and to the result of the application of the function to the previous element of the vector. The first element is being given the initial value.
So if I define the function to fold as A f(A, B), the folding of this function will be equivalent to (for 4 elements):
f(f(f(f(A_initial_value, B_0), B_1), B_2), B_3);
(capitalized prefix is there just to enforce type)
Now, more precisely fusion fold. It will fold the function on all the elements inside the boost::fusion::vector<>. As a boost::fusion::vector<X, Y> is equivalent to a std::tuple<X,Y> it will call f on different types:
A_final_value = f(A_initial_value, X_value), Y_value);
So, when you do:
my_array[k] = boost::fusion::fold(my_vec, 1, some_struct);
my_array[k] will receive an numeric value, and that won't compile since you've defined it as fusion::vector<X,Y>
So having trying to clarify fold, I would say no to your question, but I admit that I do not understand what you mean by "add the correct number of elements to the fusion::vector<X,Y>".
EDIT: Updating according what've been said in comment.
The goal isto generate a fibonacci sequence in your std::array<fusion::vector<int, int, int, int>> such as walking each vector of the array will give the fibonacci in the right order.
Using fusion you have to pass a state while iterating through the elements of the vector and so foldwas a good choice.
Here is my suggestion for this (but starting the fibonacci sequence at the second element and not the first, cause I didn't bother to handle the special case... sorry :) ):
template <typename Value>
struct Generator
{
// Easier to read and mandatory for fold
typedef typename std::tuple<Value, Value> result_type;
// The function that generate the fibonacci and update the Value
result_type operator()(result_type previous, Value& elem) const
{
elem = std::get<0>(previous) + std::get<1>(previous);
return std::make_tuple(std::get<1>(previous), elem);
}
};
// Use template to be a bit more generic on array size and vector type
template <typename Vector, size_t array_size, typename Value>
void func2(std::array<Vector, array_size>& array, std::tuple<Value, Value> init)
{
// The state that will be fed across the fold function
auto previous = init;
for (auto& vect: array)
{
// Generate the fibonnaci value for every element of the vector starting
// from where the state is. The return value of fold is the new state
previous = boost::fusion::fold(vect, previous, Generator<Value>());
}
}
// Tool to print the vector
struct Printer
{
template <typename Elem>
void operator()(const Elem& elem) const
{
std::cout << elem << std::endl;
}
};
// Use template to be a bit more generic on array size and vector type
template <typename Vector, size_t array_size, typename Value>
void func1(std::tuple<Value, Value> init)
{
// Create the vector
std::array<Vector, array_size> array;
// FIll it with fibonacci
func2(array, init);
// Print it
for (auto vect: array)
{
boost::fusion::for_each(vect, Printer());
}
}
http://rextester.com/XCXYX58360