I have two vectors. One that actually holds the data (let's say floats) and one that holds the indices. I want to pass at nth_element the indices vector, but I want the comparison to be done by the vector that actually holds the data. I was thinking about a functor, but this provides only the () operator I guess. I achieved that by making the data vector a global one, but of course that's not desired.
std::vector<float> v; // data vector (global)
bool myfunction (int i,int j) { return (v[i]<v[j]); }
int find_median(std::vector<int> &v_i)
{
size_t n = v_i.size() / 2;
nth_element(v_i.begin(), v_i.begin()+n, v_i.end(), myfunction);
return v_i[n];
}
You may use a functor like:
class comp_with_indirection
{
public:
explicit comp_with_indirection(const std::vector<float>& floats) :
floats(floats)
{}
bool operator() (int lhs, int rhs) const { return floats[lhs] < floats[rhs]; }
private:
const std::vector<float>& floats;
};
And then you may use it like:
int find_median(const std::vector<float>& v_f, std::vector<int> &v_i)
{
assert(!v_i.empty());
assert(v_i.size() <= v_f.size());
const size_t n = v_i.size() / 2;
std::nth_element(v_i.begin(), v_i.begin() + n, v_i.end(), comp_with_indirection(v_f));
return v_i[n];
}
Note: with C++11, you may use lambda instead of named functor class.
int find_median(const std::vector<float>& v_f, std::vector<int> &v_i)
{
assert(!v_i.empty());
assert(v_i.size() <= v_f.size());
const size_t n = v_i.size() / 2;
std::nth_element(
v_i.begin(), v_i.begin() + n, v_i.end(),
[&v_f](int lhs, int rhs) {
return v_f[lhs] < v_f[rhs];
});
return v_i[n];
}
Related
Alright, so I'm trying to create a Matrix class, and I really, really, want to be able to call elements by using brackets. In the style of mMatrix[x][y].
So I have a vector<vector<T>> member, and when overloading the [] operator, I return a reference to a vector<T> object.
template<class T>
class Matrix
{
private:
uint32_t DimensionHorizontal;
uint32_t DimensionVertical;
std::vector<std::vector<T>> matrix;
public:
Matrix()
{
DimensionHorizontal = 10;
DimensionVertical = 10;
}
std::vector<T>& operator[] (int index)
{
return matrix.[index];
}
Matrix(int x, int y)
{
DimensionHorizontal = x;
DimensionVertical = y;
}
};
This seems to be working because when I create a Matrix object, and try to add an element by doing Matrix[a][n] (using integers in this case), it compiles without issues. I later try to print out the value stored there with cout.
During runtime, I get the following error
Expression: vector subscript out of range on Line 1455 of the vector.
On line 1455:
_NODISCARD size_type capacity() const noexcept { // return current length of allocated storage
auto& _My_data = _Mypair._Myval2;
return static_cast<size_type>(_My_data._Myend - _My_data._Myfirst);
}
_NODISCARD _Ty& operator[](const size_type _Pos) noexcept { // strengthened
auto& _My_data = _Mypair._Myval2;
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(
_Pos < static_cast<size_type>(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return _My_data._Myfirst[_Pos];
}
I am sort of confused about why this is happening. I know I'm trying to access something out of bounds, or doing something otherwise illegal, but Matrix[] should return a vector, and I should be able to use [] again to access the element T (in this case int), any help would be appreciated.
EDIT:
This is how I use the class
int main()
{
Matrix<int> a(10, 10);
a[0][0] = 10;
std::cout << a[0][0];
return 0;
}
You need to resize the matrix in your constructor to match the size passed as arguments.
Matrix(int x, int y) : matrix(x)
{
for( auto& sub : matrix ) {
sub.resize(y);
}
DimensionHorizontal = x;
DimensionVertical = y;
}
In my program, I had a std::vector<std::array<float, n_channels>> vecvec, where n_channels was a constant integer known at compile time. In the program, vecvec grows over time.
I now want to lift the constraint that n_channels must be known at compile time, so I changed the definition to std::vector<std::vector<float>> vecvec. n_channels is still a fixed value, which is known before vecvec is constructed (all elements of vecvec have the same length).
However, now my program is suddenly about 2.5x slower.
I assume this is because the memory of vecvec is suddenly fragmented, because it doesn't "know" that every element of vecvec will have the same size.
Is there a way I can have my cake and eat it too?
Do you want to have your cake and eat it too? Implement your own row-resizable 2D array class TODAY!!!
You can write your own 2D array class. By making rows contiguous in memory, you get all the benefits of using std::vector<std::array<...>>, but without the fixed compiletime sizes! To simplify the implementation, you can make it wrap std::vector.
In order to achieve full functionality, we should also create two "helper" classes. One of them represents a row in the array, and the other represents an iterator for that row. When we iterate through the 2D array, we'll be iterating over the rows of the array.
Row class
This is pretty straight-forward. It just contains a beginning and end pointer. The array is stored contiguously, so we don't actually store Rows, but it's still convenient to have them so we have a type to iterate over.
Because the Row class just represents a view of a row in the matrix, the Row class should NOT allocate or delete any memory. Additionally, I made all the member functions of the Row class constant so that operations can be performed on Rows returned directly from the RowIterator.
template<class T>
struct Row {
T* _start;
size_t _size;
// These are const because if we need the elements to be const
// We just make T const
T* begin() const noexcept { return _start; }
T* end() const noexcept { return _start + _size; }
size_t size() const noexcept { return _size; }
T& operator[](size_t index) const noexcept {
return _start[index];
}
// Implicitly convertible to Row<T const>
operator Row<T const>() const noexcept {
return {_start, _size};
}
};
RowIterator class
This one just implements the basic abilities of a random-access iterator. You can move it forward, backward, index into it, add or subtract integers from it, etc. If I subtract 5, for example, it moves back 5 rows.
template<class T>
struct RowIterator {
using value_type = Row<T>;
using element_type = Row<T>;
using reference_type = Row<T>;
using const_reference_type = Row<T>;
// Add other iterator traits as needed
Row<T> current;
void operator++() noexcept {
current._start += current._size;
}
void operator--() noexcept {
current._start -= current._size;
}
RowIterator<T> operator+(intptr_t rows) const noexcept {
return { Row<T>{current._start + rows * current._size, current._size } };
}
RowIterator<T> operator-(intptr_t rows) const noexcept {
return { Row<T>{current._start - rows * current._size, current._size } };
}
RowIterator<T>& operator+=(intptr_t rows) noexcept {
current._start += rows * current._size;
return *this;
}
RowIterator<T>& operator-=(intptr_t rows) noexcept {
current._start -= rows * current._size;
return *this;
}
Row<T> operator*() const noexcept {
return current;
}
bool operator==(RowIterator<T> other) const noexcept {
return current._start == other.current._start && current._size == other.current._size;
}
bool operator!=(RowIterator<T> other) const noexcept {
return current._start != other.current._start || current._size != other.current._size;
}
Row<T> operator[](intptr_t index) {
return (*this + index).current;
}
};
vector2D class
The 2D vector class stores it's elements contiguously in a vector, but to access them or iterator over them it returns Rows and RowIterators. Because a Row is just two values (a pointer and a size), this is really cheap to do, and the compiler should be able to optimize it easily.
Note that to preserve const correctness, I use Row<T const>, which creates a Row with constant elements. (This greatly simplifies the implementation of Row).
template<class T>
class vector2D : private std::vector<T> {
size_t rows;
size_t columns;
using std::vector<T>::data;
public:
size_t size() const noexcept {
return rows;
}
// Gets a particular row
Row<T> operator[](size_t index) noexcept {
return { data() + columns * index, columns };
}
// Get a particular row when const
Row<T const> operator[](size_t index) const noexcept {
return { data() + columns * index, columns };
}
RowIterator<T> begin() noexcept {
return { Row<T>{ data() , columns } };
}
RowIterator<T> end() noexcept {
return { Row<T>{ data() + columns * rows, columns } };
}
RowIterator<T const> begin() const noexcept {
return { Row<T const>{ data() , columns } };
}
RowIterator<T const> end() const noexcept {
return { Row<T const>{ data() + columns * rows, columns } };
}
template<size_t N>
void push_back(std::array<T, N> const& arr) {
if(arr.size() == columns) {
insert(end(), arr.begin(), arr.end());
rows++;
}
else
throw std::invalid_argument("Bad number of columns");
}
void push_back(Row<T> arr) {
if(arr.size() == columns) {
insert(end(), arr.begin(), arr.end());
rows++;
}
else
throw std::invalid_argument("Bad number of columns");
}
void push_back(Row<T const> arr) {
if(arr.size() == columns) {
insert(end(), arr.begin(), arr.end());
rows++;
}
else
throw std::invalid_argument("Bad number of columns");
}
void push_back(std::initializer_list<T> arr) {
if(arr.size() == columns) {
insert(end(), arr.begin(), arr.end());
rows++;
}
else
throw std::invalid_argument("Bad number of columns");
}
vector2D(size_t rows, size_t columns)
: std::vector<T>(rows * columns)
, rows(rows)
, columns(columns) {}
};
Benchmark results
Run the benchmark here
The benchmark results are in, and vector2D is just as fast as using a vector of arrays!!!
The test
The test has two parts:
Fill the 2D array with values
Sum all the values
To make things as general as possible, these are the functions I used. They can be used with std::vector<std::vector<...>>, std::vector<std::array<...>>, or our very own vector2D!
template<class List>
auto calculateSum2D(List const& list) {
using elem_t = std::decay_t<decltype(list[0][0])>;
elem_t initial = 0;
for(auto const& row : list) {
for(auto& elem : row) {
initial += elem;
}
}
return initial;
}
template<class List>
void fill(List& list, int rows, int cols) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
list[i][j] = i * j;
}
}
}
The results
We used Quickbench to obtain the results, and vector2D was 4.5 times faster than using a vector of vectors!
These results were obtained using the corresponding functions, written using quick bench!
// Benchmark using a vector of vectors
static void sumVector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
std::vector<std::vector<double>> vect(rows, std::vector<double>(cols));
fill(vect, rows, cols);
auto sum = calculateSum2D(vect);
benchmark::DoNotOptimize(sum);
}
}
// Register the function as a benchmark
BENCHMARK(sumVector);
// Benchmark using a vector of arrays
static void sumArray(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
std::vector<std::array<double, cols>> vect(rows, std::array<double, cols>());
fill(vect, rows, cols);
auto sum = calculateSum2D(vect);
benchmark::DoNotOptimize(sum);
}
}
// Register the function as a benchmark
BENCHMARK(sumArray);
// Benchmark using vector2D implementation
static void sumvector2D(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
vector2D<double> vect(rows, cols);
fill(vect, rows, cols);
auto sum = calculateSum2D(vect);
benchmark::DoNotOptimize(sum);
}
}
// Register the function as a benchmark
BENCHMARK(sumvector2D);
Benchmarks v2: no repeated allocation
View benchmark 2 here
As it turns out, in the initial benchmark, most of the cost came from repeated allocations (in all cases, the object was re-allocated each iteration of the benchmark). To fix this, I moved the declaration out of the loop, so that it'd only occur once. I also adjusted the number of rows and columns so that there were more rows and fewer columns, so as to get a more realistic scenario where not the entire thing fits in the cache.
Once again, vector2D and vector<array> perform nearly identically, however this time vector<vector> does a much better job, and the gap is not nearly so impressive.
The reason for the difference in speedup is that this time around, the only differences were the result of poor cache locality, as each object was only being allocated once.
Summary
Based on the benchmark results, vector2D should bump your performance back up to what it was originally. Because your code presumably contains a mix of allocations and usage, you got a result somewhere between the two benchmarks (2.5 times slower for vector of vector). Because vector2D is contiguous and avoids the repeated heap allocations that plagued the vector-of-vector approach, it should be just as fast as a vector of arrays.
here is the C++ sample
int a[1000] = {3,1,5,4}
int b[1000] = {7,9,11,3}
how do i make it so if i sort array a, array b also following array a
example
a[1000] = {1,3,4,5}
b[1000] = {9,7,3,11}
is it possible using sort function
sort(a,a+4)
but also sort array b aswell ?
edit: what if there are 3 arrays ?
Instead of using two arrays, can you use an array of pairs and then sort THAT using a special comparison functor rather than the default less-than operator?
The simplest way is to rearrange your data into an array-of-structs instead of a pair of arrays so that each datum is contiguous; then, you can use an appropriate comparator. For example:
struct CompareFirst
{
bool operator() (const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
{
return lhs.first < rhs.first;
}
};
// c[i].first contains a[i], c[i].second contains b[i] for all i
std::pair<int, int> c[1000];
std::sort(c, c+1000, CompareFirst());
If you can't refactor your data like that, then you need to define a custom class that acts as a RandomAccessIterator:
struct ParallalArraySortHelper
{
ParallelArraySortHelper(int *first, int *second)
: a(first), b(second)
{
}
int& operator[] (int index) { return a[index]; }
int operator[] const (int index) { return a[index]; }
ParallelArraySortHelper operator += (int distance)
{
a += distance;
b += distance;
return *this;
}
// etc.
// Rest of the RandomAccessIterator requirements left as an exercise
int *a;
int *b;
};
...
int a[1000] = {...};
int b[1000] = {...};
std::sort(ParallalArraySortHelper(a, b), ParallelArraySortHelper(a+1000, b+1000));
Generate an array the same size as the original, containing the indexes into the array: {0, 1, 2, 3}. Now use a custom comparator functor that compares the elements in an associated array rather than the indexes themselves.
template<typename T>
class CompareIndices
{
public:
CompareIndices(const T * array) : m_AssociatedArray(array) {}
bool operator() (int left, int right) const
{
return std::less(m_AssociatedArray[left], m_AssociatedArray[right]);
}
private:
const T * m_AssociatedArray;
};
std::sort(i, i+4, CompareIndices(a));
Once you have a sorted list of indices, you can apply it to the original array a, or any other b array you want.
I need to dynamically allocate 1-D and 2-D arrays whose sizes are given at run-time.
I managed to "discover" std::vector and I think it fits my purposes, but I would like to ask whether what I've written is correct and/or can be improved.
This is what I'm doing:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
Dynamically allocating arrays is required when your dimensions are given at runtime, as you've discovered.
However, std::vector is already a wrapper around this process, so dynamically allocating vectors is like a double positive. It's redundant.
Just write (C++98):
#include <vector>
typedef std::vector< std::vector<double> > matrix;
matrix name(sizeX, std::vector<double>(sizeY));
or (C++11 and later):
#include <vector>
using matrix = std::vector<std::vector<double>>;
matrix name(sizeX, std::vector<double>(sizeY));
You're conflating two issues, dynamic allocation and resizable containers. You don't need to worry about dynamic allocation, since your container does that for you already, so just say it like this:
matrix name(sizeX, std::vector<double>(sizeY));
This will make name an object with automatic storage duration, and you can access its members via name[i][j].
What you're doing should basically work, however:
In general, don't dynamically allocate objects
If you want a vector, do this:
std::vector<double> vec(size);
not this:
std::vector<double>* vec = new std::vector<double>(size);
The latter gives you a pointer, which you have to delete. The former gives you a vector which, when it goes out of scope, cleans up after itself. (Internally, of course, it dynamically allocates objects, but the trick is that this is handled by the class itself, and you don't need to worry about it in your user code).
It is correct but could be made more efficient.
You could use the boost multidimensional arrays:
http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html
Or, you can implement your own class for it and handle the indexing yourself.
Perhaps something like this (which is not well tested):
#include <vector>
#include <cassert>
template <typename T, typename A = std::allocator<T> >
class Array2d
{
public:
typedef Array2d<T> self;
typedef std::vector<T, A> Storage;
typedef typename Storage::iterator iterator;
typedef typename Storage::const_iterator const_iterator;
Array2d() : major_(0), minor_(0) {}
Array2d(size_t major, size_t minor)
: major_(major)
, minor_(minor)
, storage_(major * minor)
{}
template <typename U>
Array2d(size_t major, size_t minor, U const& init)
: major_(major)
, minor_(minor)
, storage_(major * minor, u)
{
}
iterator begin() { return storage_.begin(); }
const_iterator begin() const { return storage_.begin(); }
iterator end() { return storage_.end(); }
const_iterator end() const { return storage_.end(); }
iterator begin(size_t major) {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
const_iterator begin(size_t major) const {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
iterator end(size_t major) {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
const_iterator end(size_t major) const {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
void clear() {
storage_.clear();
major_ = 0;
minor_ = 0;
}
void clearResize(size_t major, size_t minor)
{
clear();
storage_.resize(major * minor);
major_ = major;
minor_ = minor;
}
void resize(size_t major, size_t minor)
{
if ((major != major_) && (minor != minor_))
{
Array2d tmp(major, minor);
swap(tmp);
// Get minimum minor axis
size_t const dist = (tmp.minor_ < minor_) ? tmp.minor_ : minor_;
size_t m = 0;
// copy values across
for (; (m < tmp.major_) && (m < major_); ++m) {
std::copy(tmp.begin(m), tmp.begin(m) + dist, begin(m));
}
}
}
void swap(self& other)
{
storage_.swap(other.storage_);
std::swap(major_, other.major_);
std::swap(minor_, other.minor_);
}
size_t minor() const {
return minor_;
}
size_t major() const {
return major_;
}
T* buffer() { return &storage_[0]; }
T const* buffer() const { return &storage_[0]; }
bool empty() const {
return storage_.empty();
}
template <typename ArrRef, typename Ref>
class MajorProxy
{
ArrRef arr_;
size_t major_;
public:
MajorProxy(ArrRef arr, size_t major)
: arr_(arr)
, major_(major)
{}
Ref operator[](size_t index) const {
assert(index < arr_.minor());
return *(arr_.buffer() + (index + (major_ * arr_.minor())));
}
};
MajorProxy<self&, T&>
operator[](size_t major) {
return MajorProxy<self&, T&>(*this, major);
}
MajorProxy<self const&, T const&>
operator[](size_t major) const {
return MajorProxy<self&, T&>(*this, major);
}
private:
size_t major_;
size_t minor_;
Storage storage_;
};
While the points the other answers made were very correct (don't dynamically allocate the vector via new, but rather let the vector do the allocation), if you are thinking terms of vectors and matrices (e.g. linear algebra), you might want to consider using the Eigen matrix library.
You don't allocate containers dynamically. They can automatically manage memory for you if they themselves are not manually managed.
A vector grows when you add new items with push_back (or insert), you can choose its size from the start with arguments to the constructor, and you can resize it later with the resize method.
Creating a vector of vectors with your sizes with the constructor looks like this:
std::vector< std::vector<double> > matrix(size, std::vector<double>(sizeY));
This means: size instances of a std::vector<double>, each containing sizeY doubles (initialized to 0.0).
Sometimes you don't want to fill your stack and your memory requirement is large. Hence you may want to use vector> created dynamically especially while creating a table of a given row and col values.
Here is my take on this in C++11
int main() {
int row, col;
std::cin >> row >> col;
auto *arr = new std::vector<std::vector<int>*>(row);
for (int i=0; i<row; i++) {
auto *x = new std::vector<int>(col, 5);
(*arr)[i] = x;
}
for (int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
std::cout << arr->at(i)->at(j) << " ";
}
std::cout << std::endl;
}
return 0;
}
#include < iostream >
#include < vector >
using namespace std;
int main(){
vector<int>*v = new vector<int>(); // for 1d vector just copy paste it
v->push_back(5);
v->push_back(10);
v->push_back(20);
v->push_back(25);
for(int i=0;i<v->size();i++){
cout<<v->at(i)<<" ";
}
cout<<endl;
delete v;
system("pause");
return 0;
}
If you don't need to resize the array sizes at run time, then you can just use standard arrays (allocated at runtime)!
However, if you do need to resize arrays at runtime, then you can use the following (revised) code:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
In essence, all I've done is remove a single bracket (().
I need to get an input N from the user and generate a N*N matrix. How can I declare the matrix? Generally, the size of the array and matrix should be fixed at the declaration, right?
What about vector<vector<int>> ? I never use this before so I need suggestion from veteran.
A vector<vector<int>> (or vector<vector<int> >, for older compilers) can work well, but it's not necessarily the most efficient way to do things1. Another that can work quite nicely is a wrapper around a single vector, that keeps track of the "shape" of the matrix being represented, and provides a function or overloaded operator to access the data:
template <class T>
class matrix {
int columns_;
std::vector<T> data;
public:
matrix(int columns, int rows) : columns_(columns), data(columns*rows) {}
T &operator()(int column, int row) { return data[row*columns_+column]; }
};
Note that the C++ standard only allows operator[] to take a single operand, so you can't use it for this job, at least directly. In the example above, I've (obviously enough) used operator() instead, so subscripts look more like Fortran or BASIC than you're accustomed to in C++. If you're really set on using [] notation, you can do it anyway, though it's mildly tricky (you overload it in the matrix class to return a proxy, then have the proxy class also overload operator[] to return (a reference to) the correct element -- it's mildly ugly internally, but works perfectly well anyway).
Here's an example of how to implement the version using multiple overloads of operator[]. I wrote this (quite a while) before most compilers included std::vector, so it statically allocates an array instead of using a vector. It's also for the 3D case (so there are two levels of proxies involved), but with a bit of luck, the basic idea comes through anyway:
template<class T, int size>
class matrix3 {
T data[size][size][size];
friend class proxy;
friend class proxy2;
class proxy {
matrix3 &m_;
int index1_, index2_;
public:
proxy(matrix3 &m, int i1, int i2)
: m_(m), index1_(i1), index2_(i2)
{}
T &operator[](int index3) {
return m_.data[index1_][index2_][index3];
}
};
class proxy2 {
matrix3 &m_;
int index_;
public:
proxy2(matrix3 &m, int d) : m_(m), index_(d) { }
proxy operator[](int index2) {
return proxy(m_, index_, index2);
}
};
public:
proxy2 operator[](int index) {
return proxy2(*this, index);
}
};
Using this, you can address the matrix with the normal C++ syntax, such as:
matrix3<double, size> m;
for (int x=0; x<size; x++)
for (int y = 0; y<size; y++)
for (int z = 0; z<size; z++)
m[x][y][z] = x*100 + y * 10 + z;
An std::vector is normally implemented as a pointer to some dynamically allocated data, so something like a vector<vector<vector<int>>> will dereference two levels of pointers to get to each piece of data. This means more memory references, which tend to be fairly slow on most modern processors. Since each vector contains separately allocated data, it also leads to poor cache locality as a rule. It can also waste some space, since each vector stores both its allocated size and the size in use.
Boost implements matrices (supporting mathematical operations) in its uBLAS library, and provides usage syntax like the following.
#include <boost/numeric/ublas/matrix.hpp>
int main(int argc, char* argv[])
{
unsigned int N = atoi(argv[1]);
boost::matrix<int> myMatrix(N, N);
for (unsigned i = 0; i < myMatrix.size1 (); ++i)
for (unsigned j = 0; j < myMatrix.size2 (); ++j)
myMatrix(i, j) = 3 * i + j;
return 0;
}
Sample Code:
template<class T>
class Array2D
{
public:
Array2D(int a, int b)
{
num1 = (T**)new int [a*sizeof(int*)];
for(int i = 0; i < a; i++)
num1[i] = new int [b*sizeof(int)];
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
num1[i][j] = i*j;
}
}
}
class Array1D
{
public:
Array1D(int* a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
T* temp;
};
T** num1;
Array1D operator[] (int a)
{
return Array1D(num1[a]);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Array2D<int> arr(20, 30);
std::cout << arr[2][3];
getchar();
return 0;
}
enter code here