How to make my std::vector implementation faster? [duplicate] - c++

This question already has an answer here:
How to get feedback on design [closed]
(1 answer)
Closed 8 years ago.
I am trying to write an implementation of std::vector to learn C++ and my implementation is slower than std::vector (see output).
I am wondering how I can improve it from any C++ experts. I saw this question (Why is std::vector so fast ( or is my implementation is too slow )) but his problem didn't help as the poster was using the wrong data structure.
I am asking how I can get it faster than std::vector.
vector.h
template <typename T>
class Vector {
public:
explicit Vector(const int n);
explicit Vector(const int n, const T& val);
T& operator[](const int i);
inline int const length();
inline void fill(const T& val);
private:
T* arr;
int len;
};
vector.cpp
#include "vector.h"
#include <iostream>
#include <algorithm>
using namespace std;
template <typename T>
inline void Vector<T>::fill(const T& val)
{
for (int i = 0; i < len; ++i) {
arr[i] = val;
}
}
template <typename T>
inline T& Vector<T>::sum()
{
T total = 0;
for (int i = 0; i < len; ++i) {
total += arr[i];
}
return total;
}
template <typename T>
Vector<T>::Vector(const int n) : arr(new T[n]()), len(n)
{
//cout << "Vector(n)" <<'\n';
}
template <typename T>
Vector<T>::Vector(const int n, const T& val) : arr(new T[n]), len(n)
{
//cout << "Vector(n, val)" <<'\n';
for (int i = 0; i < len; ++i) {
arr[i] = val;
}
}
template <typename T>
T& Vector<T>::operator[](const int i)
{
return arr[i];
}
template <typename T>
int const Vector<T>::length()
{
return len;
}
template class Vector<int>;
template class Vector<float>;
vector_test.cpp
#include "vector.h"
#include <iostream>
#include <chrono>
#include <vector>
using namespace std;
int main()
{
const int n = 2000000;
float sum = 0;
chrono::steady_clock::time_point start = chrono::steady_clock::now();
Vector<float> vec(n, 1);
sum = vec.sum();
chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
cout << "my vec sum = " << sum << '\n';
cout << "my vec impl took " << chrono::duration_cast<chrono::microseconds>(end - start).count()
<< "us.\n";
sum = 0;
start = chrono::steady_clock::now();
vector<float> vec2(n, 1);
for (int i = 0; i < n; ++i) {
sum += vec2[i];
}
end = std::chrono::steady_clock::now();
cout << "std::vec sum = " << sum << '\n';
cout << "stl::vec impl took " << chrono::duration_cast<chrono::microseconds>(end - start).count()
<< "us.\n";
}
Output:
my vec sum = 2e+06
my vec impl took 11040us.
std::vec sum = 2e+06
stl::vec impl took 8034us.

This is quite naive code since on every iteration the index is reevaluated (and you hope the optimizer will optimize it away):
for (int i = 0; i < len; ++i) {
arr[i] = val;
}
Here is a somewhat better way:
T* ptr = arr;
T* end = ptr + len;
while ( ptr < end ) *ptr++ = val;
However, a good compiler will indeed do this transformation.
The same idea can be applied to Sum():
template <typename T> inline T Vector<T>::sum()
{
T* ptr = arr;
T* end = ptr + len;
T total = 0;
while ( ptr < end ) total += *ptr++;
return total;
}

Related

How to Print whole array inside square brackets rather then printing every single value?

In the following code I want to print the whole array instead of printing each single value. Can we do that? I'm familiar with python where we append values but I can't find that in C++. So how to get desired result. What if I have to print it using printf?
#include <iostream>
using namespace std;
int *name(){
static int n[5];
for(int i=0;i<5;i++){
n[i]=i;}
return n;}
int main(){
int *p;
p=name();
for(int i=0;i<5;i++){
cout<<*(p+i)<<endl;}
return 0;
desired output should be -
[0,1,2,3,4]
#include <iostream>
using namespace std;
int *name() {
static int n[5];
for (int i = 0; i < 5; ++i)
n[i] = i;
return n;
}
int main()
{
int *p;
p = name();
cout << '[';
for (int i = 0; i < 5; ++i)
cout << *(p+i) << (i != 4 ? ',' : ']');
}
Or, if you want to encapsulate the array-printing into a general function:
#include <iostream>
#include <string>
using namespace std;
std::string PrintArray(int* array, size_t size) {
std::string answer = "[";
for (size_t i = 0; i < size; ++i) {
answer += std::to_string(array[i]);
answer += (i < size-1) ? "," : "]";
}
return answer;
}
int* name() {
static int n[5];
for (int i = 0; i < 5; i++) {
n[i] = i;
}
return n;
}
int main() {
int* p;
p = name();
cout << PrintArray(p, 5) << endl;
return 0;
}
I usually end up overloading operator<< for the desired type, but your mileage may vary.
#include <iostream>
#include <vector>
template <class InputIt>
std::ostream& print_impl(std::ostream& os, InputIt first, InputIt last)
{
os << '[';
if (first != last)
{
os << *first;
while ( ++first != last )
os << ", " << *first;
}
return os << ']';
}
template <class T>
std::ostream& operator<<(std::ostream& os, std::vector<T> const& v)
{
return print_impl(os, v.cbegin(), v.cend());
}
template <class T, size_t N>
std::ostream& operator<<(std::ostream& os, T const (&a)[N])
{
return print_impl(os, std::cbegin(a), std::cend(a));
}
int main()
{
std::vector<int> a{1, 2, 3, 4, 5};
std::cout << a << '\n';
float b[] = {3.14f, -0.1f, 2.0f};
std::cout << b << '\n';
}

reading a CSV file while working with template

I am new to C++ so what I am trying to do is, reading a CSV file in my function readRecord(readRecord() templated function). In my CSV file I have stored some data such as years and crime, crime rate etc and display it using display function. I posted my code so far but it is giving me error I am not sure about how to make it work. can someone help me out please?
#ifndef SICT_DATA_H
#define SICT_DATA_H
#include <fstream>
#include <iomanip>
namespace sict {
const int LARGEST_NUMBER = 1000000000; // 1,000,000,000
const int SMALLEST_NUMBER = 0;
const int COLUMN_WIDTH = 15;
template <typename T>
T max(const T* data, int n)
{
int maximum = data[0];
for (int i = 0; i < n; i++)
{
if (data[i] > maximum)
{
maximum = data[i];
//*data = maximum;
}
}
return maximum;
}
template <typename T>
T min(const T* data, int n)
{
T minimum = data[0];
for (int i = 0; i < n; i++)
{
if ((dataa[i] < minimum) && (data[i] >= SMALLEST_NUMBER))
{
minimum = data[i];
//*data = minimum;
}
}
return minimum;
}
template <typename T>
T sum(const T* data, int n)
{
double sum;
for (int i = 0; i <= n; i++)
{
sum = sum + data[i];
}
return sum;
}
template <typename T>
double average(const T* data, int n)
{
double average;
for (int i = 0; i <= n; i++)
{
average = (sum(data, n) / n);
}
return average;
}
template <typename T>
bool read(std::istream& input, T* data, int n)
{
char comma;
for (int i = 0; i < n; i++)
{
input >> comma >> data[i];
if (cin.fail())
{
return false;
}
}
return true;
}
template <typename T>
void readRecord()
{
ifstream ip("crimedata.csv");
int year[5];
int pop[5];
int crime[5];
int rate[5];
int autoo[5];
int rate1[5];
while (ip.EOF())
{
for (int i = 0; i < 5 i++)
{
getline(ip.year[i], ',');
getline(ip.pop[i], ',');
getline(ip.crime[i], ',');
getline(ip.rate[i], ',');
getline(ip.autoo[i], ',');
getline(ip.rate1[i], '\n');
cout << year[i] << pop[i] << crime[i] << endl;
}
}
ip.close;
}
template <typename T>
void display(const char* name, const T* data, int n)
{
readRecord();
cout << setw(20) << name ;
cout << setw(15) << data << endl;
}
}
#endif
Csv File:
5
Year 2000 2001 2002 2003 2004
Population 281421906 285317559 287973924 290788976 293656842
ViolentCrime 1425486 1439480 1423677 1383676 1360088
ViolentCrime_Rate 506.5 504.5 494.4 475.8 463.2
GrandTheftAuto 1160002 1228391 1246646 1261226 1237851
GrandTheftAuto_Rate 412.2 430.5 432.9 433.7 421.5

How to Add two multi-dimensional std::vectors (without using operator+)?

The algorithm is simple and straight-forward:
Keep break the n dimensional vector into n-1 dimensional constituent vectors, until you have access to the basic-datatype objects. Their addition is simple and well-defined.
Here is my implementation using templates and operator+:
#include <iostream>
#include <vector>
template<class T>
std::vector<T> operator+ (const std::vector<T>& v1, const std::vector<T>& v2)
{
std::vector<T> output;
unsigned len = v1.size();
output.resize(len);
for (int i = 0; i < len; ++i)
output[i] = v1[i] + v2[i];
return output;
}
int main ()
{
using namespace std;
vector<std::vector<int>> x = {{8,9,0},{5,6,7}};
vector<std::vector<int>> y = {{1,1,1},{1,1,1}};
auto result = x + y; // Yeah, just like that !
// Being Lazy, instead of implementing multi-dimensional vector printing...
for (int i = 0; i < result.size(); ++i)
{
for (int j=0; j<result[i].size(); ++j)
cout << result.at(i).at(j) << " ";
cout << "\n";
}
return 0;
}
But suppose you are not allowed to use operator+.
You have to design an interface as some function Add().
But I'm unable to do so!! Here's my attempt:
#include <iostream>
#include <vector>
// Hoping to handle vectors...
template<class T>
std::vector<T> Add (const std::vector<T>& v1, const std::vector<T>& v2)
{
std::vector<T> output;
unsigned len = v1.size();
output.resize(len);
for (int i = 0; i < len; ++i)
output[i] = Add(v1[i], v2[i]);
return output;
}
// Hoping to handle basic-datatypes...
template<class T>
T Add (const T& v1, const T& v2)
{
T output;
unsigned len = v1.size();
output.resize(len);
for (int i = 0; i < len; ++i)
output[i] = v1[i] + v2[i];
return output;
}
int main ()
{
using namespace std;
vector<std::vector<int>> x = {{8,9,0},{5,6,7}};
vector<std::vector<int>> y = {{1,1,1},{1,1,1}};
auto result = Add(x, y); // I wish ! But not happening !
// Being Lazy, instead of implementing multi-dimensional vector printing...
for (int i = 0; i < result.size(); ++i)
{
for (int j=0; j<result[i].size(); ++j)
cout << result.at(i).at(j) << " ";
cout << "\n";
}
return 0;
}
Is it even possible?
You must provide a version for Add() that works on basic data types
// Handle basic-datatypes
template<class T>
T Add(const T& x1, const T& x2)
{
return x1 + x2;
}
// Specialisation for vectors
template<class T>
std::vector<T> Add(std::vector<T> const& v1, std::vector<T> const& v2)
{
assert(v1.size()==v2.size());
std::vector<T> result;
result.reserve(v1.size());
for(size_t i=0; i!=v1.size(); ++i)
result.emplace_back(Add(v1[i],v2[i])); // possibly recursive
return result;
}
Instead of this:
// Hoping to handle basic-datatypes...
template<class T>
T Add (const T& v1, const T& v2)
{
T output;
unsigned len = v1.size();
output.resize(len);
for (int i = 0; i < len; ++i)
output[i] = v1[i] + v2[i];
return output;
}
It has to be:
// Hoping to handle basic-datatypes...
template<class T>
T Add (const T& v1, const T& v2)
{
return v1 + v2;
}
Also the one which handles basic-datatypes must come before the one which handles vectors.

Heapsort order of magnitude slower than Bubblesort (C++)

I have implemented a heap data structure, and use it to sort. My understanding is that it is O(nlogn) complexity. However, when compared to bubble sort, it is order of magnitude slower -- and yeah, I tried running it for larger arrays. I checked some answers at SO (in particular this and this), but still lost. Could anyone point out what am I doing wrong here, please?
The results are:
HEAP SORT: 12415690ns
QUICK SORT: 71ns
BUBBLE SORT: 541659ns
Here are the codes:
main.cpp:
#include <chrono>
#include <iostream>
#include <stdexcept>
#include <vector>
// #include "heap.cpp"
// #include "pqueue.cpp"
#include "sort.cpp"
using namespace std;
using namespace std::chrono;
template <class T>
void printVector (vector<T> A) {
for (std::vector<int>::iterator it = A.begin(); it != A.end(); ++it) {
std::cout << *it << ' ';
}
cout << endl;
}
template <class T>
vector<T> constructVector(int A[], std::size_t len, std::size_t num) {
vector<T> res (A, A+len);
for (std::size_t idx = 0; idx < num-1; ++idx) {
res.push_back(A[idx%len]);
}
return res;
}
int main() {
high_resolution_clock::time_point t1;
high_resolution_clock::time_point t2;
int a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
std::size_t len = sizeof(a) / sizeof(int);
vector<int> HEAP = constructVector<int>(a, len, 32000); // (a, a + sizeof(a) / sizeof(int));
vector<int> QUICK = constructVector<int>(a, len, 32000); // (a, a + sizeof(a) / sizeof(int));
vector<int> BUBBLE = constructVector<int>(a, len, 32000);
// cout << "Original Array: "; printVector(HEAP);
cout << "HEAP SORT: ";
t1 = high_resolution_clock::now();
heapsort(HEAP);
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
// cout << "Original Array: "; printVector(QUICK);
cout << "QUICK SORT: ";
t1 = high_resolution_clock::now();
quicksort(QUICK, 0, QUICK.size());
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
// cout << "Original Array: "; printVector(QUICK);
cout << "BUBBLE SORT: ";
t1 = high_resolution_clock::now();
bublesort(BUBBLE);
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
}
sort.cpp:
#ifndef __SORT_CPP_INCLUDED_
#define __SORT_CPP_INCLUDED_
#include <vector>
#include "heap.cpp"
template <class T>
void heapsort(std::vector<T> &A, bool increasing = true) {
Heap<T> H(A, increasing);
H.sort();
A = H.get();
}
template <class T>
std::size_t partition(std::vector<T> &A, std::size_t p, std::size_t r) {
T x = A[r-1];
std::size_t i = p - 1;
for (std::size_t j = p; j < r; ++j) {
if (A[j] <= x) {
++i;
A[i] ^= A[j];
A[j] ^= A[i];
A[i] ^= A[j];
}
}
A[i+1] ^= A[r-1];
A[r-1] ^= A[i+1];
A[i+1] ^= A[r-1];
return i + 1;
}
template <class T>
void quicksort(std::vector<T> &A, std::size_t p, std::size_t r) {
if (p-1 < r) {
std::size_t q = partition(A, p, r);
quicksort(A, p, q);
quicksort(A, q+1, r);
}
}
template <class T>
void bublesort(std::vector<T> &A) {
bool swapped = false;
do {
swapped = false;
for (std::size_t idx = 1; idx < A.size(); ++idx) {
if (A[idx-1] > A[idx]) {
// swap them
A[idx] = A[idx-1];
A[idx-1] = A[idx];
A[idx] = A[idx-1];
swapped = true;
}
}
} while (swapped);
}
#endif
heap.cpp:
#ifndef __HEAP_CPP_INCLUDED__
#define __HEAP_CPP_INCLUDED__
#include <vector>
template <class T>
class Heap {
public:
Heap(bool maxHeap = true) : heap_size(0), max_heap(maxHeap) {}
Heap(const std::vector<T> &a, bool maxHeap = true) : A(a), max_heap(maxHeap) {
if (maxHeap) this->build_max_heap(); else this->build_min_heap(); }
~Heap() {}
protected:
std::vector<T> A;
std::size_t heap_size;
bool max_heap;
public:
std::size_t parent(std::size_t idx) { return (idx - 1) >> 1; }
std::size_t left(std::size_t idx) { return (idx << 1) + 1; }
std::size_t right (std::size_t idx) { return (idx + 1) << 1; }
public:
std::vector<T> get() { return A; }
std::size_t size() { return heap_size; }
void sort();
void build_max_heap();
void build_min_heap();
void max_heapify(std::size_t idx);
void min_heapify(std::size_t idx);
};
template <class T>
void Heap<T>::sort() {
if (this->heap_size <= 0) return; // Already sorted or empty
if (this->heap_size != this->A.size()){ // Not sorted and not heapified
max_heap ? build_max_heap() : build_min_heap();
}
for (std::size_t idx = this->A.size()-1; idx > 0; --idx) {
A[0] ^= A[idx];
A[idx] ^= A[0];
A[0] ^= A[idx];
--this->heap_size;
max_heap ? max_heapify(0) : min_heapify(0);
}
}
template<class T>
void Heap<T>::build_max_heap() {
this->heap_size = this->A.size();
for (std::size_t idx = (this->A.size() - 1) >> 1; idx > 0; --idx)
this->max_heapify(idx);
this->max_heapify(0);
}
template<class T>
void Heap<T>::build_min_heap() {
this->heap_size = this->A.size();
for (std::size_t idx = (this->A.size()-1) >> 1; idx > 0; --idx)
this->min_heapify(idx);
this->min_heapify(0);
}
template <class T>
void Heap<T>::max_heapify(std::size_t idx) {
std::size_t l = this->left(idx);
std::size_t r = this->right(idx);
std::size_t largest;
if (l < this->heap_size && A[l] > A[idx]) largest = l;
else largest = idx;
if (r < this->heap_size && A[r] > A[largest]) largest = r;
if (largest != idx) {
this->A[idx] ^= this->A[largest];
this->A[largest] ^= this->A[idx];
this->A[idx] ^= this->A[largest];
this->max_heapify(largest);
}
}
template <class T>
void Heap<T>::min_heapify(std::size_t idx) {
std::size_t l = this->left(idx);
std::size_t r = this->right(idx);
std::size_t smallest;
// std::cout << "DEBUG: " << idx << std::endl;
if (l < this->heap_size && A[l] < A[idx]) smallest = l;
else smallest = idx;
if (r < this->heap_size && A[r] < A[smallest]) smallest = r;
if (smallest != idx) {
this->A[idx] ^= this->A[smallest];
this->A[smallest] ^= this->A[idx];
this->A[idx] ^= this->A[smallest];
this->min_heapify(smallest);
}
}
#endif
Your bubble sort doesn't swap, but only copy. This would make it somewhat faster. Not sure this alone explains being so fast, though.
Your Heap<T> makes a copy of the array. This can explain the slowness. I guess you forgot a &.
You should have noticed 71ns to sort 32k array is not real. Your quicksort never sorts anything. You can use std::sort for a reliable quicksort.
Too much is known at compile time and the numbers are far from random. Switch to arrays with random numbers in this kind of testing.

Cartesian Product in c++

I have been searching for weeks on how to come up with piece of code which I could applied the cartesian product. Let's say I have two arrays :
int M[2]= {1,2};
int J[3] = {0,1,2};
So the code will takes those two arrays in apply the rule M X J
therefore we will have the pairs (1,0)(1,1)(1,2)(2,0)(2,1)(2,2) and I want the new result to be saved into a new array where each index in the array contains a pair , for example c[0] = (1,0).
Help please :(
Here is an implementation where the sequences of values is a parameter (rather than pre-known as in all the other implementations):
void CartesianRecurse(vector<vector<int>> &accum, vector<int> stack,
vector<vector<int>> sequences, int index)
{
vector<int> sequence = sequences[index];
for (int i : sequence)
{
stack.push_back(i);
if (index == 0)
accum.push_back(stack);
else
CartesianRecurse(accum, stack, sequences, index - 1);
stack.pop_back();
}
}
vector<vector<int>> CartesianProduct(vector<vector<int>> sequences)
{
vector<vector<int>> accum;
vector<int> stack;
if (sequences.size() > 0)
CartesianRecurse(accum, stack, sequences, sequences.size() - 1);
return accum;
}
main() {
vector<vector<int>> sequences = { {1,2,7},{3,4},{5,6} };
vector<vector<int>> res = CartesianProduct(sequences);
// now do something with the result in 'res'.
}
#include <iostream>
#include <iterator>
#include <vector>
#include <utility>
#include <tuple>
template<typename Range1, typename Range2, typename OutputIterator>
void cartesian_product(Range1 const &r1, Range2 const &r2, OutputIterator out) {
using std::begin; using std::end;
for (auto i = begin(r1);i != end(r1); ++i) {
for (auto j = begin(r2); j != end(r2); ++j) {
*out++ = std::make_tuple(*i, *j);
}
}
}
int main() {
std::vector<int> a{1,2,3};
std::vector<char> b{'a','b','c','d','e','f'};
std::vector<std::tuple<int, char>> c;
cartesian_product(a, b, back_inserter(c));
for (auto &&v : c) {
std::cout << "(" << std::get<int>(v) << "," << std::get<char>(v) << ")";
}
}
Prints:
(1,a)(1,b)(1,c)(1,d)(1,e)(1,f)(2,a)(2,b)(2,c)(2,d)(2,e)(2,f)(3,a)(3,b)(3,c)(3,d)(3,e)(3,f)
And you can also apply the function to your case:
template<typename T, int N> constexpr int size(T (&)[N]) { return N; }
int main() {
int M[2] = {1,2};
int J[3] = {0,1,2};
std::tuple<int, int> product[size(M) * size(J)];
cartesian_product(M, J, product);
for (auto &&v : product) {
std::cout << "(" << std::get<0>(v) << "," << std::get<1>(v) << ")";
}
}
The output is:
(1,0)(1,1)(1,2)(2,0)(2,1)(2,2)
http://coliru.stacked-crooked.com/a/3ce388e10c61a3a4
Here is an simple example of implementing Cartesian product using vector. Vectors are much better choice as we do not need to worry about its size as it dynamically changes it.
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
int main() {
int M[2]= {1,2};
int J[3] = {0,1,2};
vector<pair<int,int>> C;
for (int i = 0; i < sizeof(M)/sizeof(M[0]); i++)
{
for (int j = 0; j < sizeof(J)/sizeof(J[1]); j++)
{
C.push_back(make_pair(M[i],J[j]));
}
}
/*
for (vector<int>::iterator it = C.begin(); it != C.end(); it++)
{
cout << *it << endl;
}
*/
for (int i = 0; i < C.size(); i++)
{
cout << C[i].first << "," << C[i].second << endl;
}
}
Here is the link where I implemented the above code. Although I wouldn't post solution directly relating to your question, links posted in the comments already contains answer which is why I posted.
I think using of c++ two-dimensional arrays is a very bad idea, but if you want, you probably could use this code
#include <iostream>
int** cartesian_prod( int* s1, int* s2, int s1size, int s2size )
{
int ressize = s1size*s2size;
int** res = new int*[ressize];
for ( int i = 0; i < s1size; i++ )
for ( int j = 0; j < s2size; j++ )
{
res[i*s2size+j] = new int[2];
res[i*s2size+j][0] = s1[i];
res[i*s2size+j][1] = s2[j];
}
return res;
}
int main() {
int M[2]= {1,2};
int J[3] = {0,1,2};
int** res;
int Msize = sizeof(M)/sizeof(M[0]);
int Jsize = sizeof(J)/sizeof(J[1]);
res = cartesian_prod(M, J, Msize, Jsize);
for ( int i = 0; i < Msize*Jsize; i++ )
std::cout << res[i][0] << " " << res[i][1] << std::endl;
for (int i = 0; i < Msize*Jsize; i++)
delete[] res[i];
delete[] res;
return 0;
}
But it is much better to deal with std::vector - it much faster (in terms of development time) and will save you from many errors.
Solution without for loops.
#include<array>
#include<iostream>
#include<tuple>
#include<utility>
template
<typename T, typename Tuple, std::size_t... I>
auto cartesian_product_base(
const T& a,
const Tuple& t,
std::index_sequence<I...>) {
return std::make_tuple(std::make_pair(a, std::get<I>(t))...);
}
template
<typename T, typename... Ts, std::size_t... I>
std::array<T, sizeof...(Ts) + 1> to_array(std::tuple<T, Ts...> t, std::index_sequence<I...>) {
return {std::get<I>(t)...};
}
template
<typename Tuple1, typename Tuple2, std::size_t... I>
auto cartesian_product_impl(
const Tuple1& t1,
const Tuple2& t2,
std::index_sequence<I...>) {
return std::tuple_cat(cartesian_product_base(
std::get<I>(t1),
t2,
std::make_index_sequence<std::tuple_size<Tuple2>::value>{})...);
}
template
<typename T1, std::size_t N1, typename T2, std::size_t N2>
auto cartesian_product(
const std::array<T1, N1>& a1,
const std::array<T2, N2>& a2) {
return to_array(
cartesian_product_impl(a1, a2, std::make_index_sequence<N1>{}),
std::make_index_sequence<N1 * N2>{});
}
using namespace std;
int main() {
array<int, 2> M = {1, 2};
array<int, 3> J = {0, 1, 2};
auto C = cartesian_product(M, J);
cout << C.size() << endl;
cout << "{";
for (size_t i = 0; i != C.size(); ++i) {
if (i != 0) {
cout << ", ";
}
cout << "(" << C[i].first << ", " << C[i].second << ")";
}
cout << "}" << endl;
}