Apakah mungkin membebani []
operator dua kali? Untuk mengizinkan, sesuatu seperti ini: function[3][3]
(seperti dalam array dua dimensi).
Jika memungkinkan, saya ingin melihat beberapa contoh kode.
c++
operator-overloading
icepopo.dll
sumber
sumber
operator()(int, int)
...std::vector
dengan konstruktor rentang: stackoverflow.com/a/25405865/610351using array2d = std::array<std::array<int, 3>, 3>;
Jawaban:
Anda bisa membebani
operator[]
untuk mengembalikan objek yang bisa Anda gunakanoperator[]
lagi untuk mendapatkan hasil.class ArrayOfArrays { public: ArrayOfArrays() { _arrayofarrays = new int*[10]; for(int i = 0; i < 10; ++i) _arrayofarrays[i] = new int[10]; } class Proxy { public: Proxy(int* _array) : _array(_array) { } int operator[](int index) { return _array[index]; } private: int* _array; }; Proxy operator[](int index) { return Proxy(_arrayofarrays[index]); } private: int** _arrayofarrays; };
Kemudian Anda bisa menggunakannya seperti:
ArrayOfArrays aoa; aoa[3][5];
Ini hanyalah contoh sederhana, Anda ingin menambahkan banyak pemeriksaan batas dan semacamnya, tetapi Anda mengerti.
sumber
Proxy::operator[]
harus kembaliint&
tidak hanyaint
std::vector<std::vector<int>>
untuk menghindari perilaku memleak dan aneh pada salinan.multi_array
danextent_gen
merupakan contoh bagus dari teknik ini. boost.org/doc/libs/1_57_0/libs/multi_array/doc/…const ArrayOfArrays arr; arr[3][5] = 42;
akan mampu melewati kompilasi dan perubahanarr[3][5]
, yang entah bagaimana berbeda dari apa harapan pengguna yangarr
adalahconst
.Proxy::operator[]
tidak mengembalikan referensi dalam kode ini (dengan asumsi komentar Anda tidak membalas Ryan Haining). Lebih penting lagi, jikaarr
adalah const makaoperator[]
tidak dapat digunakan. Anda harus mendefinisikan versi const, dan tentu saja Anda akan membuatnya kembaliconst Proxy
. MakaProxy
itu sendiri akan memiliki metode const dan non-const. Dan kemudian contoh Anda masih belum dapat dikompilasi, dan programmer akan senang bahwa semuanya baik-baik saja di alam semesta. =)Ekspresi
x[y][z]
mengharuskanx[y]
mengevaluasi objekd
yang mendukungd[z]
.Ini berarti bahwa
x[y]
harus menjadi objek denganoperator[]
yang mengevaluasi ke "objek proxy" yang juga mendukungoperator[]
.Ini adalah satu-satunya cara untuk merantai mereka.
Atau, lakukan overload
operator()
untuk mengambil beberapa argumen, seperti yang mungkin Anda panggilmyObject(x,y)
.sumber
Untuk larik dua dimensi, khususnya, Anda mungkin lolos dengan kelebihan beban operator [] yang mengembalikan penunjuk ke elemen pertama dari setiap baris.
Kemudian Anda dapat menggunakan operator pengindeksan bawaan untuk mengakses setiap elemen dalam baris.
sumber
Hal ini dimungkinkan jika Anda mengembalikan beberapa jenis kelas proxy dalam panggilan [] pertama. Namun, ada opsi lain: Anda bisa membebani operator () yang bisa menerima sejumlah argumen (
function(3,3)
).sumber
Salah satu pendekatannya menggunakan
std::pair<int,int>
:class Array2D { int** m_p2dArray; public: int operator[](const std::pair<int,int>& Index) { return m_p2dArray[Index.first][Index.second]; } }; int main() { Array2D theArray; pair<int, int> theIndex(2,3); int nValue; nValue = theArray[theIndex]; }
Tentu saja, Anda mungkin
typedef
sajapair<int,int>
sumber
nValue = theArray[{2,3}];
Anda dapat menggunakan objek proxy, seperti ini:
#include <iostream> struct Object { struct Proxy { Object *mObj; int mI; Proxy(Object *obj, int i) : mObj(obj), mI(i) { } int operator[](int j) { return mI * j; } }; Proxy operator[](int i) { return Proxy(this, i); } }; int main() { Object o; std::cout << o[2][3] << std::endl; }
sumber
Akan sangat bagus jika Anda bisa memberi tahu saya apa
function
,function[x]
dan apafunction[x][y]
adanya. Tapi bagaimanapun izinkan saya menganggapnya sebagai objek yang dideklarasikan di suatu tempat(Karena Anda mengatakan bahwa operator itu kelebihan beban, saya pikir Anda tidak akan tertarik pada array seperti
SomeClass function[16][32];
)Jadi
function
adalah contoh tipeSomeClass
. Kemudian cari deklarasiSomeClass
untuk jenisoperator[]
kelebihan muatan yang dikembalikan , sepertiReturnType operator[](ParamType);
Kemudian
function[x]
akan memiliki tipeReturnType
. Lagi mencariReturnType
untukoperator[]
overload. Jika ada metode seperti itu, Anda dapat menggunakan ekspresifunction[x][y]
.Catatan, tidak seperti
function(x, y)
,function[x][y]
ada 2 panggilan terpisah. Jadi, sulit bagi kompiler atau runtime untuk menjamin atomicity kecuali Anda menggunakan kunci dalam konteksnya. Contoh serupa adalah, libc mengatakanprintf
adalah atom sementara panggilan berturut-turut ke kelebihan bebanoperator<<
dalam aliran keluaran tidak. Pernyataan sepertistd::cout << "hello" << std::endl;
mungkin ada masalah dalam aplikasi multi-utas, tetapi sesuatu seperti
printf("%s%s", "hello", "\n");
baik-baik saja.
sumber
#include<iostream> using namespace std; class Array { private: int *p; public: int length; Array(int size = 0): length(size) { p=new int(length); } int& operator [](const int k) { return p[k]; } }; class Matrix { private: Array *p; public: int r,c; Matrix(int i=0, int j=0):r(i), c(j) { p= new Array[r]; } Array& operator [](const int& i) { return p[i]; } }; /*Driver program*/ int main() { Matrix M1(3,3); /*for checking purpose*/ M1[2][2]=5; }
sumber
struct test { using array_reference = int(&)[32][32]; array_reference operator [] (std::size_t index) { return m_data[index]; } private: int m_data[32][32][32]; };
Menemukan solusi sederhana saya sendiri untuk ini.
sumber
template<class F> struct indexer_t{ F f; template<class I> std::result_of_t<F const&(I)> operator[](I&&i)const{ return f(std::forward<I>(i))1; } }; template<class F> indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}
Ini memungkinkan Anda mengambil lambda, dan menghasilkan pengindeks (dengan
[]
dukungan).Misalkan Anda memiliki
operator()
yang mendukung penerusan kedua koordinat di onxe sebagai dua argumen. Sekarang[][]
dukungan menulis hanyalah:auto operator[](size_t i){ return as_indexer( [i,this](size_t j)->decltype(auto) {return (*this)(i,j);} ); } auto operator[](size_t i)const{ return as_indexer( [i,this](size_t j)->decltype(auto) {return (*this)(i,j);} ); }
Dan selesai. Tidak ada kelas khusus yang diperlukan.
sumber
Jika, alih-alih mengucapkan [x] [y], Anda ingin mengucapkan [{x, y}], Anda dapat melakukan seperti ini:
struct Coordinate { int x, y; } class Matrix { int** data; operator[](Coordinate c) { return data[c.y][c.x]; } }
sumber
Dimungkinkan untuk membebani lebih dari satu [] menggunakan penangan template khusus. Hanya untuk menunjukkan cara kerjanya:
#include <iostream> #include <algorithm> #include <numeric> #include <tuple> #include <array> using namespace std; // the number '3' is the number of [] to overload (fixed at compile time) struct TestClass : public SubscriptHandler<TestClass,int,int,3> { // the arguments will be packed in reverse order into a std::array of size 3 // and the last [] will forward them to callSubscript() int callSubscript(array<int,3>& v) { return accumulate(v.begin(),v.end(),0); } }; int main() { TestClass a; cout<<a[3][2][9]; // prints 14 (3+2+9) return 0; }
Dan sekarang definisi
SubscriptHandler<ClassType,ArgType,RetType,N>
untuk membuat kode sebelumnya berfungsi. Itu hanya menunjukkan bagaimana itu bisa dilakukan. Solusi ini optimal atau bebas bug (tidak threadsafe misalnya).#include <iostream> #include <algorithm> #include <numeric> #include <tuple> #include <array> using namespace std; template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler; template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ { ClassType*obj; array<ArgType,N+1> *arr; typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype; friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>; friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>; public: Subtype operator[](const ArgType& arg){ Subtype s; s.obj = obj; s.arr = arr; arr->at(Recursion)=arg; return s; } }; template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> { ClassType*obj; array<ArgType,N+1> *arr; friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>; friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>; public: RetType operator[](const ArgType& arg){ arr->at(0) = arg; return obj->callSubscript(*arr); } }; template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{ array<ArgType,N> arr; ClassType*ptr; typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype; protected: SubscriptHandler() { ptr=(ClassType*)this; } public: Subtype operator[](const ArgType& arg){ Subtype s; s.arr=&arr; s.obj=ptr; s.arr->at(N-1)=arg; return s; } }; template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{ RetType operator[](const ArgType&arg) { array<ArgType,1> arr; arr.at(0)=arg; return ((ClassType*)this)->callSubscript(arr); } };
sumber
Dengan a
std::vector<std::vector<type*>>
, Anda dapat membuat vektor bagian dalam menggunakan operator input khusus yang mengulangi data Anda dan mengembalikan pointer ke setiap data.Sebagai contoh:
size_t w, h; int* myData = retrieveData(&w, &h); std::vector<std::vector<int*> > data; data.reserve(w); template<typename T> struct myIterator : public std::iterator<std::input_iterator_tag, T*> { myIterator(T* data) : _data(data) {} T* _data; bool operator==(const myIterator& rhs){return rhs.data == data;} bool operator!=(const myIterator& rhs){return rhs.data != data;} T* operator*(){return data;} T* operator->(){return data;} myIterator& operator++(){data = &data[1]; return *this; } }; for (size_t i = 0; i < w; ++i) { data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]), myIterator<int>(&myData[(i + 1) * h]))); }
Contoh langsung
Solusi ini memiliki keuntungan karena memberi Anda wadah STL nyata, sehingga Anda dapat menggunakan khusus untuk loop, algoritma STL, dan sebagainya.
for (size_t i = 0; i < w; ++i) for (size_t j = 0; j < h; ++j) std::cout << *data[i][j] << std::endl;
Namun, itu membuat vektor pointer, jadi jika Anda menggunakan struktur data kecil seperti ini, Anda dapat langsung menyalin konten di dalam larik.
sumber
Kode sampel:
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; }
sumber
vektor <vektor <T>> atau T ** diperlukan hanya jika Anda memiliki baris dengan panjang variabel dan terlalu tidak efisien dalam hal alokasi / penggunaan memori jika Anda memerlukan larik persegi panjang, pertimbangkan untuk melakukan matematika sebagai gantinya! lihat di metode ():
template<typename T > class array2d { protected: std::vector< T > _dataStore; size_t _sx; public: array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {} T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; } const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; } const T& get( size_t x, size_t y ) const { return at(x,y); } void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; } };
sumber
Menggunakan C ++ 11 dan Perpustakaan Standar Anda dapat membuat larik dua dimensi yang sangat bagus dalam satu baris kode:
std::array<std::array<int, columnCount>, rowCount> myMatrix {0}; std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix; std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;
Dengan memutuskan matriks dalam mewakili baris, Anda mengakses matriks dengan
myMatrix[y][x]
sintaks:myMatrix[0][0] = 1; myMatrix[0][3] = 2; myMatrix[3][4] = 3; std::cout << myMatrix[3][4]; // outputs 3 myStringMatrix[2][4] = "foo"; myWidgetMatrix[1][5].doTheStuff();
Dan Anda dapat menggunakan ranged-
for
untuk keluaran:for (const auto &row : myMatrix) { for (const auto &elem : row) { std::cout << elem << " "; } std::cout << std::endl; }
(Memutuskan
array
kolom mewakili bagian dalam akan memungkinkan untukfoo[x][y]
sintaks tetapi Anda harus menggunakanfor(;;)
loop yang lebih kaku untuk menampilkan output.)sumber
5 sen saya.
Saya secara intuitif tahu saya perlu melakukan banyak kode boilerplate.
Inilah sebabnya, alih-alih operator [], saya melakukan operator yang kelebihan beban (int, int). Kemudian di hasil akhir, alih-alih m [1] [2], saya lakukan m (1,2)
Saya tahu ini adalah hal yang BERBEDA, tetapi masih sangat intuitif dan terlihat seperti skrip matematika.
sumber
Solusi terpendek dan termudah:
class Matrix { public: float m_matrix[4][4]; // for statements like matrix[0][0] = 1; float* operator [] (int index) { return m_matrix[index]; } // for statements like matrix[0][0] = otherMatrix[0][0]; const float* operator [] (int index) const { return m_matrix[index]; } };
sumber