เป็นไปได้ไหมที่จะโอเวอร์โหลด[]
ตัวดำเนินการสองครั้ง ในการอนุญาตสิ่งนี้: function[3][3]
(เช่นในอาร์เรย์สองมิติ)
ถ้าเป็นไปได้ฉันต้องการดูโค้ดตัวอย่าง
เป็นไปได้ไหมที่จะโอเวอร์โหลด[]
ตัวดำเนินการสองครั้ง ในการอนุญาตสิ่งนี้: function[3][3]
(เช่นในอาร์เรย์สองมิติ)
ถ้าเป็นไปได้ฉันต้องการดูโค้ดตัวอย่าง
std::vector
กับ range constructor: stackoverflow.com/a/25405865/610351
using array2d = std::array<std::array<int, 3>, 3>;
คำตอบ:
คุณสามารถโอเวอร์โหลดoperator[]
เพื่อส่งคืนอ็อบเจ็กต์ที่คุณสามารถใช้operator[]
อีกครั้งเพื่อให้ได้ผลลัพธ์
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;
};
จากนั้นคุณสามารถใช้มันได้เช่น:
ArrayOfArrays aoa;
aoa[3][5];
นี่เป็นเพียงตัวอย่างง่ายๆคุณต้องการเพิ่มการตรวจสอบขอบเขตและสิ่งต่างๆมากมาย แต่คุณได้รับแนวคิด
Proxy::operator[]
ควรกลับint&
ไม่ได้เป็นเพียงint
std::vector<std::vector<int>>
เพื่อหลีกเลี่ยง memleak และพฤติกรรมแปลก ๆ ในการคัดลอก
multi_array
และextent_gen
เป็นตัวอย่างที่ดีของเทคนิคนี้ boost.org/doc/libs/1_57_0/libs/multi_array/doc/…
const ArrayOfArrays arr; arr[3][5] = 42;
จะสามารถที่จะผ่านการรวบรวมและการเปลี่ยนแปลงarr[3][5]
ซึ่งเป็นอย่างใดแตกต่างจากสิ่งที่คาดหวังของผู้ใช้ที่เป็นarr
const
Proxy::operator[]
อย่าส่งคืนข้อมูลอ้างอิงในรหัสนี้ (สมมติว่าความคิดเห็นของคุณไม่ได้ตอบกลับ Ryan Haining) ที่สำคัญถ้าarr
เป็น const แล้วoperator[]
จะไม่สามารถใช้งานได้ คุณจะต้องกำหนดเวอร์ชัน const และแน่นอนว่าคุณจะต้องคืนconst Proxy
ค่า จากนั้นProxy
ตัวมันเองจะมีวิธี const และ non-const จากนั้นตัวอย่างของคุณก็ยังไม่สามารถรวบรวมได้และโปรแกรมเมอร์ก็ยินดีที่ทุกอย่างเรียบร้อยและดีในจักรวาล =)
การแสดงออกx[y][z]
ต้องการให้x[y]
ประเมินไปยังวัตถุที่สนับสนุนd
d[z]
ซึ่งหมายความว่าx[y]
ควรจะเป็นวัตถุที่มีoperator[]
ประเมินว่าเป็น "วัตถุพร็อกซี่" ที่ยังoperator[]
สนับสนุน
นี่เป็นวิธีเดียวที่จะล่ามโซ่พวกเขา
อีกทางเลือกหนึ่งเกินที่จะใช้ข้อโต้แย้งหลายอย่างเช่นที่คุณอาจเรียกoperator()
myObject(x,y)
สำหรับอาร์เรย์สองมิติโดยเฉพาะคุณอาจหนีไปได้ด้วยตัวดำเนินการเดียว [] โอเวอร์โหลดที่ส่งกลับตัวชี้ไปยังองค์ประกอบแรกของแต่ละแถว
จากนั้นคุณสามารถใช้ตัวดำเนินการจัดทำดัชนีในตัวเพื่อเข้าถึงแต่ละองค์ประกอบภายในแถว
เป็นไปได้ถ้าคุณส่งคืนคลาสพร็อกซีบางประเภทในการโทร [] ครั้งแรก อย่างไรก็ตามมีตัวเลือกอื่น: คุณสามารถโอเวอร์โหลดตัวดำเนินการ () ที่สามารถรับอาร์กิวเมนต์จำนวนเท่าใดก็ได้ ( function(3,3)
)
แนวทางหนึ่งคือการใช้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];
}
แน่นอนคุณอาจtypedef
pair<int,int>
nValue = theArray[{2,3}];
คุณสามารถใช้วัตถุพร็อกซีได้ดังนี้:
#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;
}
มันจะดีหากคุณสามารถให้เราทราบว่าfunction
, function[x]
และfunction[x][y]
มี แต่อย่างไรก็ตามขอผมพิจารณาว่ามันเป็นวัตถุที่ประกาศที่ไหนสักแห่งเช่น
SomeClass function;
(เพราะคุณบอกว่ามันเกินตัวดำเนินการฉันคิดว่าคุณจะไม่สนใจอาร์เรย์SomeClass function[16][32];
)
ดังนั้นเป็นตัวอย่างของประเภทfunction
SomeClass
จากนั้นค้นหาคำประกาศSomeClass
สำหรับประเภทการส่งคืนของการ operator[]
โอเวอร์โหลดเช่นเดียวกับ
ReturnType operator[](ParamType);
แล้วfunction[x]
จะมีประเภทReturnType
. มองหาReturnType
การoperator[]
โอเวอร์โหลดอีกครั้ง หากมีวิธีการดังกล่าวคุณสามารถใช้นิพจน์function[x][y]
ได้
หมายเหตุที่แตกต่างfunction(x, y)
กันfunction[x][y]
คือ 2 สายแยกกัน ดังนั้นจึงเป็นเรื่องยากสำหรับคอมไพเลอร์หรือรันไทม์รับประกันความเป็นอะตอมเว้นแต่คุณจะใช้การล็อกในบริบท ตัวอย่างที่คล้ายกันคือ libc กล่าวว่าprintf
เป็นอะตอมในขณะที่การเรียกต่อเนื่องไปยังoperator<<
กระแสข้อมูลที่โอเวอร์โหลด คำสั่งเช่น
std::cout << "hello" << std::endl;
อาจมีปัญหาในแอปพลิเคชันมัลติเธรด แต่บางอย่างเช่น
printf("%s%s", "hello", "\n");
สบายดี.
#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;
}
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];
};
พบวิธีง่ายๆของตัวเองสำหรับเรื่องนี้
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)};}
วิธีนี้ช่วยให้คุณใช้แลมด้าและสร้างดัชนี (พร้อม[]
การสนับสนุน)
สมมติว่าคุณมีoperator()
ที่รองรับการส่งผ่านพิกัดทั้งสองที่ onxe เป็นสองอาร์กิวเมนต์ ตอนนี้การ[][]
สนับสนุนการเขียนเป็นเพียง:
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);}
);
}
และเสร็จแล้ว ไม่จำเป็นต้องมีคลาสที่กำหนดเอง
ถ้าแทนที่จะพูดว่า [x] [y] คุณต้องการพูดว่า [{x, y}] คุณสามารถทำได้ดังนี้:
struct Coordinate { int x, y; }
class Matrix {
int** data;
operator[](Coordinate c) {
return data[c.y][c.x];
}
}
เป็นไปได้ที่จะโอเวอร์โหลด [] หลายรายการโดยใช้ตัวจัดการเทมเพลตพิเศษ เพียงเพื่อแสดงวิธีการทำงาน:
#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;
}
และตอนนี้คำจำกัดความของSubscriptHandler<ClassType,ArgType,RetType,N>
การทำให้รหัสก่อนหน้านี้ทำงานได้ มันแสดงให้เห็นว่าทำได้เท่านั้น โซลูชันนี้เหมาะสมที่สุดหรือปราศจากข้อบกพร่อง (เช่นไม่ปลอดภัยสำหรับเธรด)
#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);
}
};
ด้วย a std::vector<std::vector<type*>>
คุณสามารถสร้างเวกเตอร์ภายในโดยใช้ตัวดำเนินการป้อนข้อมูลที่กำหนดเองซึ่งวนซ้ำข้อมูลของคุณและส่งกลับตัวชี้ไปยังข้อมูลแต่ละรายการ
ตัวอย่างเช่น:
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])));
}
โซลูชันนี้มีข้อได้เปรียบในการจัดหาคอนเทนเนอร์ STL จริงให้คุณดังนั้นคุณจึงสามารถใช้แบบพิเศษสำหรับลูปอัลกอริทึม STL และอื่น ๆ
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
อย่างไรก็ตามมันสร้างเวกเตอร์ของพอยน์เตอร์ดังนั้นหากคุณใช้โครงสร้างข้อมูลขนาดเล็กเช่นโครงสร้างนี้คุณสามารถคัดลอกเนื้อหาภายในอาร์เรย์ได้โดยตรง
โค้ดตัวอย่าง:
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;
}
จำเป็นต้องใช้ vector <vector <T>> หรือ T ** ก็ต่อเมื่อคุณมีแถวที่มีความยาวตัวแปรและไม่มีประสิทธิภาพมากเกินไปในแง่ของการใช้ / การจัดสรรหน่วยความจำหากคุณต้องการอาร์เรย์สี่เหลี่ยมให้ลองคำนวณทางคณิตศาสตร์แทน! ดูที่ () วิธีการ:
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; }
};
การใช้ C ++ 11 และ Standard Library คุณสามารถสร้างอาร์เรย์สองมิติที่ดีมากในโค้ดบรรทัดเดียว:
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;
ด้วยการตัดสินใจว่าเมทริกซ์ภายในแสดงถึงแถวคุณจะเข้าถึงเมทริกซ์ด้วยmyMatrix[y][x]
ไวยากรณ์:
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();
และคุณสามารถใช้ ranged- for
สำหรับเอาต์พุต:
for (const auto &row : myMatrix) {
for (const auto &elem : row) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
(การตัดสินใจว่าarray
คอลัมน์แสดงด้านในจะอนุญาตให้ใช้foo[x][y]
ไวยากรณ์ได้ แต่คุณต้องใช้for(;;)
ลูปที่clumsier เพื่อแสดงผลลัพธ์)
5 เซ็นต์ของฉัน
ฉันรู้โดยสัญชาตญาณว่าฉันต้องทำรหัสสำเร็จรูปจำนวนมาก
ด้วยเหตุนี้แทนที่จะเป็นตัวดำเนินการ [] ฉันใช้ตัวดำเนินการมากเกินไป (int, int) จากนั้นผลสุดท้ายแทนที่จะเป็น m [1] [2] ฉันได้ m (1,2)
ฉันรู้ว่ามันเป็นสิ่งที่แตกต่างกัน แต่ก็ยังใช้งานง่ายมากและดูเหมือนสคริปต์ทางคณิตศาสตร์
วิธีแก้ปัญหาที่สั้นและง่ายที่สุด:
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];
}
};
operator()(int, int)
แทน ...