Operator overloading template parameter - c++

So I have a little class that implements a matrix. Everything works well, except whatever gave me the reason to post here. I've explained more about the problem in the actual code, using comments. Thanks in advance to anyone that can help! This is not the entire program, but it is big enough so that it can compile on its own.
#include <iostream>
#include <initializer_list>
template<class type_t, unsigned Rows, unsigned Columns>
class matrix
{
private:
std::initializer_list<std::initializer_list<type_t>> elements;
public:
type_t contents[Rows][Columns];
matrix() {}
matrix(const std::initializer_list<std::initializer_list<type_t>> &container)
: elements(container)
{
unsigned i = 0;
for (const auto &el : elements)
{
unsigned j = 0;
for (const auto &num : el)
{
contents[i][j] = num;
j++;
}
i++;
}
}
unsigned rows() { return Rows; }
unsigned columns() { return Columns; }
type_t &operator()(const unsigned &i, const unsigned &j)
{
return contents[i][j];
}
template<unsigned rws, unsigned cls>
auto operator*(matrix<type_t, rws, cls> &mat)
{
matrix<type_t, Rows, 3> ret_mat; //OK, but only in case the return matrix has 3 columns
matrix<type_t, Rows, mat.columns()> ret_mat; //Error. This is the desired result
//The error message tells me it needs to be a compile-time constant
//it's pretty obvious why the first works and what the problem is
//but i still have no idea how to get past this
for (unsigned i = 0; i < this->rows(); ++i)
{
for (unsigned j = 0; j < mat.columns(); ++j)
{
for (unsigned in = 0; in < 2; ++in)
ret_mat.contents[i][j] += this->contents[i][in] * mat.contents[in][j];
}
}
return ret_mat;
}
};
int main()
{
matrix<int, 4, 2> mat = { { 7, 3 },{ 2, 5 },{ 6, 8 },{ 9, 0 } };
matrix<int, 2, 3> mat2 = { { 7, 4, 9 },{ 8, 1, 5 } };
auto mat3 = mat * mat2;
for (unsigned i = 0; i < mat3.rows(); ++i)
{
for (unsigned j = 0; j < mat3.columns(); ++j)
std::cout << mat3(i, j) << " ";
std::cout << std::endl;
}
std::cin.get();
}

template<unsigned rws, unsigned cls>
You already have desired expressions!
matrix<type_t, Rows, cls> ret;
Edit: as mentioned by #juanchopanza, why are you allowing multiplication of N*M on K*L with M != K? Should be
template<unsigned cls>
auto operator*(matrix<type_t, columns, cls> &mat)
{
matrix<type_t, Rows, cls> ret_mat;

Related

How to sort the columns of a 2D vector by a specific row?

I have a 2D vector, and i would like to sort all its columns by a sorting a specific row (the inner vectors) like this:
input:
{{5,6,9},
{1,7,5},
{3,5,7}}
sorting the elements to asc in row 2, the vector would be:
{{5,9,6},
{1,5,7},
{3,7,5}}
If stl sort is an acceptable choice, you can do like this:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
// According to your description, the input is row major
vector<vector<int>> vec_2d{
{5,6,9},
{1,7,5},
{3,5,7} };
// Convert the input vec to col major
int rows = vec_2d.size();
int cols = vec_2d.front().size();
// Allocate a new 2d vec which stores values by col major
vector<vector<int>> vec_2d_col_major(cols, vector<int>(rows));
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
vec_2d_col_major[j][i] = vec_2d[i][j];
}
}
// Sort by asc the 2nd row
sort(vec_2d_col_major.begin(), vec_2d_col_major.end(), [](const vector<int>& a, vector<int>& b) {
return a[1] < b[1];
});
// Copy data from col major to row major
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
vec_2d[i][j] = vec_2d_col_major[j][i];
}
}
// Check the sort result
for (const auto& row : vec_2d) {
for (auto num : row) {
cout << num << " ";
}
cout << endl;
}
}
Output:
5 9 6
1 5 7
3 7 5
I suppose your input vector is stored in row major by std::vector
sorted by reorder, use a vector to keep the order for each column.
#include <vector>
#include <algorithm>
#include <iostream>
template<class T>
void show(const std::vector<std::vector<T>>& values) {
for (auto& raw : values) {
for (auto& v : raw)
std::cout << v << " ";
std::cout << std::endl;
}
}
template<class T>
void swap(std::vector<std::vector<T>>& values, uint32_t i, uint32_t j) {
for (auto& row : values)
std::swap(row[i], row[j]);
}
template<class T>
void reorder(std::vector<std::vector<T>>& values, std::vector<uint32_t>& order) {
for (uint32_t i = 0; i < order.size(); ++i) {
while (order[i] != order[order[i]]) {
swap(values, order[i], order[order[i]]);
std::swap(order[i], order[order[i]]);
}
}
}
template<class T>
void sort_row(std::vector<std::vector<T>>& values, int32_t row) {
uint32_t row_count = values.size();
uint32_t col_count = values[row].size();
std::vector<uint32_t> sorted_idx(col_count);
for (uint32_t i = 0; i < col_count; ++i)
sorted_idx[i] = i;
std::sort(sorted_idx.begin(), sorted_idx.end(),
[&](uint32_t i, uint32_t j) {
return values[row][i] < values[row][j];
});
reorder(values, sorted_idx);
}
int main(int, char**) {
std::vector<std::vector<int32_t>> values = {
{-1, -3, -2, -4},
{ 0, 1, 2, 3},
{ 5, 6, 7, 8}
};
sort_row(values, 0);
show(values);
return 0;
}

Building a submatrix from a matrix

I'm trying to split a matrix given into 4, but I'm getting some errors and I can't figure out why. I'm kind of new to the language. Does anybody knows what am I doing wrong?
void split_tl(T **matrice, unsigned int dim){
if(dim == 1){
return;
}
T **tl = new T*[dim/4];
for(unsigned int i = 0; i<dim/4;++i){
tl[i] = new T[dim/4];
}
for(unsigned int i=0; i<dim;++i){
for(unsigned int j=0; j<dim;j++){
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
} else{
std::cout << "no ";
}
}
std::cout << std::endl;
}
}
In this function I'm trying to obtain the top left corner of the matrix.
int **matrice = new int*[2];
for(unsigned int i = 0; i<2;++i){
matrice[i] = new int[2];
}
for(unsigned int i = 0; i<2;++i){
for(unsigned int j = 0; j<2;++j){
matrice[i][j] = i+j;
}
}
This is the matrix I'm sending. It is a 2x2 matrix, just for testing purposes.
These are the errors from Valgrind:
==133== Invalid read of size 8
==133== Invalid write of size 4
==133== Process terminating with default action of signal 11 (SIGSEGV)
==133== Access not within mapped region at address 0x0
If dim is the side of a matrix, allocating to a quarter matrix should be dim/2.
Below in the code you are using :
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
}
here tl may exceed the allocation
What you're doing wrong? You're allocating memory and passing pointers around.
Build a proper matrix class, e.g. (very simplified version):
template <typename T, unsigned Rows, unsigned Cols>
struct generic_matrix {
using datatype = T;
static constexpr unsigned rows = Rows;
static constexpr unsigned cols = Cols;
datatype data[rows][cols];
constexpr datatype& operator()(unsigned row, unsigned col) noexcept
{ return data[row][col]; }
constexpr const datatype& operator()(unsigned row, unsigned col) const noexcept
{ return data[row][col]; }
};
Submatrix:
/* Returns a submatrix of the matrix m,
* by deleting the row r and the column c.*/
template <typename M>
auto submatrix(const M& m, unsigned r, unsigned c) noexcept
{
generic_matrix<typename M::datatype, M::rows-1, M::cols-1> res;
for (unsigned row = 0, i = 0; row < M::rows; ++row) {
if (row == r) continue; //this row we do not want
for (unsigned col = 0, j = 0; col < M::cols; ++col) {
if (col == c) continue; //this col we do not want
res(i,j) = m(row,col);
++j;
}
++i;
}
return res;
}
Print:
template <typename M>
void printmatrix(const M& m) noexcept
{
for (unsigned r=0; r < M::rows; ++r) {
for (unsigned c=0; c < M::cols; ++c) {
std::cout << m(r,c) << ' ';
}
std::cout << '\n';
}
}
Test:
int main()
{
int n=0;
generic_matrix<int, 3, 3> m;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 3; ++c)
m(r,c) = ++n;
printmatrix(m);
std::cout << '\n';
printmatrix(submatrix(m, 0, 0));
std::cout << '\n';
printmatrix(submatrix(m, 1, 1));
std::cout << '\n';
printmatrix(submatrix(m, 2, 2));
return 0;
}
Note: It is just a hint. As you can see, no allocation nor casting is needed.

overload operator & to produce sum of int[][]

it's a test from some company.
overload & to return sum of int[][]
main()
{
int arr[5][5];
// initialization
cout << &arr; // output the sum of arr
}
I try this code but returns compile error:
long operator &(int** arr)
{
// return the sum of arr
}
error: the argument should contains class type or enumeration
currently I understand this error, but how to overload operator for buildin types?
Example of overloading operator &, only for educational use!
I would NOT recommend overloading operator& in any serious code.
#include <iostream>
struct my_array
{
my_array()
{
for (int i = 0; i < 5; ++i)
{
for (int j = 0; j < 5; ++j)
{
values[i][j] = 1 + i + j;
}
}
}
int operator&()
{
int sum = 0;
for (int i = 0; i < 5; ++i)
{
for (int j = 0; j < 5; ++j)
{
sum += values[i][j];
}
}
return sum;
}
private:
int values[5][5]{};
};
int main()
{
my_array m;
int sum = &m;
std::cout << sum;
}
I think interviewer may want you to overload operator<< actually, not & and the solution could then be like below. See it live here.
#include <iostream>
using int5x5_t = int[5][5];
std::ostream& operator<<(std::ostream& os, const int5x5_t* parr) {
long sum = 0;
for (auto& vec : *parr) {
for (auto val : vec) {
sum += val;
}
}
return os << sum;
}
int main() {
int arr[5][5] = {
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4}
};
std::cout << &arr << std::endl;
}

c++ assignment operator overloading

Hello everyone i'm trying to write an assignment operator for this class so i can assign an array like thisint[] = {0, 1, 2, 3} to my Tableau class
originally i wanted to do this
Tableau<T>& operator=(T arr[])
{
return Tableau(tab, sizeofarray);
}
because i already wrote a constructor that takes and array and the size as its argument
and i ran into a problem with the size of the the array i don't know how to find it
how can i find the size of the array or is there a better way to do this
template<typename T>
class Tableau
{
public:
Tableau(int s = 0) : size(s), ptr(new T[size])
{
for (int i = 0; i < size; i++)
{
ptr[i] = 0;
}
}
Tableau(T tab[], int s = 0) : size(s), ptr(new T[size])
{
for (int i = 0; i < size; i++)
{
ptr[i] = tab[i];
}
}
~Tableau()
{
delete[] ptr;
}
Tableau<T>& operator=( T tab[])
{
}
T commule()
{
T com = 0;
for (int i = 0; i < size; i++)
{
com += ptr[i];
}
return com;
}
T& operator[](const int index)
{
return ptr[index];
}
private:
int size;
T* ptr;
};
int main()
{
int k[] = { 8, 12, 5, 9, 55};
Tableau<int> TI(k, 2);
TI = k;
return 0;
}
You can use:
template <std::size_t N>
Tableau<T>& operator=(T (&arr)[N])
{
// This is not right.
// The returned value is a temporary.
// return Tableau(arr, N);
// Update the contents of the object.
// ...
// Then, return a reference to this object.
return *this;
}
With that member function template, when you invoke:
int k[] = { 8, 12, 5, 9, 55};
Tableau<int> TI(k, 2);
TI = k;
The operator= function is instantiated with N = 5 and k as the value of arr. Hence, you get the size of the array as well as the contents of the array.
However, it is worth pointing out that if you use:
int k[] = { 8, 12, 5, 9, 55};
int* k2 = k;
Tableau<int> TI(k, 2);
TI = k2;
it won't work. k2 is not an array. It is a pointer to an int, which happens to point to the first element of k.

Variadic nested loops

I am working on a N dimensional grid.
I would like to generate nested loops depending on any dimension (2D, 3D, 4D, etc...).
How can I do that in an elegant and fast way ? Below a simple illustration of my problem.
I am writing in C++ but I think this kind of question can be useful for other languages.
I need to know the indices (i,j,k...) in my do stuff part.
Edit : lower_bound and upper_bound represents the indexes in the grid so they are always positive.
#include <vector>
int main()
{
// Dimension here is 3D
std::vector<size_t> lower_bound({4,2,1});
std::vector<size_t> upper_bound({16,47,9});
for (size_t i = lower_bound[0]; i < upper_bound[0]; i ++)
for (size_t j = lower_bound[1]; j < upper_bound[1]; j ++)
for (size_t k = lower_bound[2]; k < upper_bound[2]; k ++)
// for (size_t l = lower_bound[3]; l < upper_bound[3]; l ++)
// ...
{
// Do stuff such as
grid({i,j,k}) = 2 * i + 3 *j - 4 * k;
// where grid size is the total number of vertices
}
}
Following may help:
bool increment(
std::vector<int>& v,
const std::vector<int>& lower,
const std::vector<int>& upper)
{
assert(v.size() == lower.size());
assert(v.size() == upper.size());
for (auto i = v.size(); i-- != 0; ) {
++v[i];
if (v[i] != upper[i]) {
return true;
}
v[i] = lower[i];
}
return false;
}
And use it that way:
int main() {
const std::vector<int> lower_bound({4,2,1});
const std::vector<int> upper_bound({6,7,4});
std::vector<int> current = lower_bound;
do {
std::copy(current.begin(), current.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
} while (increment(current, lower_bound, upper_bound));
}
Live demo
An iterative approach could look like this:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> lower_bound({-4, -5, -6});
std::vector<int> upper_bound({ 6, 7, 4});
auto increase_counters = [&](std::vector<int> &c) {
for(std::size_t i = 0; i < c.size(); ++i) {
// This bit could be made to look prettier if the indices are counted the
// other way around. Not that it really matters.
int &ctr = c .rbegin()[i];
int top = upper_bound.rbegin()[i];
int bottom = lower_bound.rbegin()[i];
// count up the innermost counter
if(ctr + 1 < top) {
++ctr;
return;
}
// if it flows over the upper bound, wrap around and continue with
// the next.
ctr = bottom;
}
// end condition. If we end up here, loop's over.
c = upper_bound;
};
for(std::vector<int> counters = lower_bound; counters != upper_bound; increase_counters(counters)) {
for(int i : counters) {
std::cout << i << ", ";
}
std::cout << "\n";
}
}
...although whether this or a recursive approach is more elegant rather depends on the use case.
#include <iostream>
#include <vector>
template <typename Func>
void process(const std::vector<int>& lower, const std::vector<int>& upper, Func f)
{
std::vector<int> temp;
process(lower, upper, f, 0, temp);
}
template <typename Func>
void process(const std::vector<int>& lower, const std::vector<int>& upper, Func f,
int index, std::vector<int>& current)
{
if (index == lower.size())
{
f(current);
return;
}
for (int i = lower[index]; i < upper[index]; ++i)
{
current.push_back(i);
process(lower, upper, f, index + 1, current);
current.pop_back();
}
}
int main()
{
// Dimension here is 3D
std::vector<int> lower_bound({-4, -5, 6});
std::vector<int> upper_bound({6, 7, 4});
// Replace the lambda below with whatever code you want to process
// the resulting permutations.
process(lower_bound, upper_bound, [](const std::vector<int>& values)
{
for (std::vector<int>::const_iterator it = values.begin(); it != values.end(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
});
}
Probably some typos an whatnot, but I'd flatten the whole range.
This is based on the idea that the range can be described as
x_0 + d_0*(x_1+d_1*(x_2+d_2....)
So we can roll our own that way
std::vector<int> lower_bound{-4,-5,6};
std::vector<int> upper_bound{6,7,4};
//ranges
std::vector<int> ranges;
for (size_t i = 0; i < lower_bound.size(); i++) {
ranges.push_back(upper_bound[i]-lower_bound[i]);
}
for (int idx = 0; idx < numel; idx++) {
//if you don't need the actual indicies, you're done
//extract indexes
int idx2 = idx;
std::vector<int> indexes;
for (int i = 0; i < ranges.size(); i++) {
indexes.push_back(idx2%ranges[i]-lower_bound[i]);
idx2 = idx2/ranges[i];
}
//do stuff
grid[idx] = 2 * indexes[0] + 3 *indexes[1] - 4 * indexes[2];
}
Edit: to be more generic:
template <typename D>
void multi_for(const std::vector<int>& lower_bound, const std::vector<int> upper_bound, D d) {
std::vector<int> ranges;
for (size_t i = 0; i < lower_bound.size(); i++) {
ranges.push_back(upper_bound[i]-lower_bound[i]);
}
size_t numel = std::accumulate(ranges.begin(), ranges.end(), std::multiplies<int,int>{});
for (int idx = 0; idx < numel; idx++) {
//if you don't need the actual indicies, you're done
//extract indexes
int idx2 = idx;
std::vector<int> indexes;
for (int i = 0; i < ranges.size(); i++) {
indexes.push_back(idx2%ranges[i]-lower_bound[i]);
idx2 = idx2/ranges[i];
}
//do stuff
d(idx,indexes);
}
}
//main
size_t* grid;//initialize to whateer
std::vector<int> lower_bound{-4,-5,6};
std::vector<int> upper_bound{6,7,4};
auto do_stuff = [grid](size_t idx, const std::vector<int> indexes) {
grid[idx] = 2 * indexes[0] + 3 *indexes[1] - 4 * indexes[2];
};
multi_for(lower_bound,upper_bound,do_stuff);
A recursive function may help you achieve what you want.
void Recursive( int comp )
{
if(comp == dimension)
{
// Do stuff
}
else
{
for (int e = lower_bound[comp]; e < upper_bound[comp]; e++)
Recursive(comp+1);
}
}
Some additions may be necessary in the function signature if you need to know the current indices (i,j,k,...) in your "Do Stuff" section.
This is a clean way to have access to these indices
void Recursive( int comp, int dimension )
{
static std::vector<int> indices;
if( comp == 0 ) // initialize indices
{
indices.clear();
indices.resize(dimension, 0);
}
if(comp == dimension -1)
{
// Do stuff
}
else
{
int& e = indices[comp];
for (e = lower_bound[comp]; e < upper_bound[comp]; e++)
Recursive(comp+1);
}
}
This is however not usable along multiple threads, due to the shared static vector.