অপারেটর [] [] ওভারলোড


93

[]দু'বার ওভারলোড করা সম্ভব ? অনুমতি দেওয়ার জন্য, এর মতো কিছু: function[3][3](একটি দ্বিমাত্রিক অ্যারের মতো)।

যদি এটি সম্ভব হয় তবে আমি কয়েকটি উদাহরণ কোড দেখতে চাই।


24
BTW, এটা জমিদার অনেক সহজ এবং আরো সাধারণ এর operator()(int, int)পরিবর্তে ...
ইনভার্স

4
চাকা পুনরুদ্ধার কেন? কেবলমাত্র std::vectorএকটি ব্যাপ্তি নির্মাণকারীর সাথে ব্যবহার করুন : stackoverflow.com/a/25405865/610351
জিওফ্রয়

অথবা আপনি ঠিক যেমন কিছু ব্যবহার করতে পারেনusing array2d = std::array<std::array<int, 3>, 3>;
অ্যাডম্বুডাক

উত্তর:


122

আপনি 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];

এটি কেবল একটি সাধারণ উদাহরণ, আপনি সীমান্তের চেক এবং স্টাফগুলির একটি গুচ্ছ যুক্ত করতে চান তবে আপনি ধারণাটি পাবেন।


4
একটি ধ্বংসকারী ব্যবহার করতে পারে। এবং কেবল Proxy::operator[]ফিরে int&আসা উচিত নয়int
রায়ান হেইনিং

4
std::vector<std::vector<int>>অনুলিপি এবং অনুলিপিতে অদ্ভুত আচরণ এড়ানোর জন্য ব্যবহার করা ভাল ।
জারোড 42

উভয়ই বুস্ট multi_arrayএবং extent_genএই কৌশলটির ভাল উদাহরণ। boost.org/doc/libs/1_57_0/libs/mult_array/doc/…
alfC

4
যাইহোক, const ArrayOfArrays arr; arr[3][5] = 42;সংকলন এবং পরিবর্তন পাস করতে সক্ষম হবে arr[3][5], যা কি ব্যবহারকারীদের প্রত্যাশা থেকে একরকম ভিন্ন arrহয় const
abcdabcd987

4
@ abcdabcd987 এটি বেশ কয়েকটি কারণে সঠিক নয়। প্রথমত, Proxy::operator[]এই কোডটিতে কোনও রেফারেন্স দেয় না (ধরে নিলেন আপনার মন্তব্য রায়ান হেইনিংয়ের উত্তরে নয়)। আরও গুরুত্বপূর্ণ, যদি arrকনস্ট থাকে তবে operator[]ব্যবহার করা যাবে না। আপনাকে একটি কনস্টের সংস্করণ সংজ্ঞায়িত করতে হবে এবং অবশ্যই আপনি এটি ফিরিয়ে আনবেন const Proxy। তারপরে Proxyনিজেই কনস্ট এবং নন-কনস্ট্যান্ড পদ্ধতি থাকত। এবং তারপরেও আপনার উদাহরণটি এখনও সংকলন করবে না এবং প্রোগ্রামার খুশি হবে যে মহাবিশ্বে সমস্ত কিছু ভাল এবং ভাল। =)
ধান

21

একটি এক্সপ্রেশন x[y][z]প্রয়োজন সমর্থন করে যে x[y]একটি অবজেক্টের মূল্যায়ন ।dd[z]

এর অর্থ এই যে x[y]একটি সঙ্গে একটি বস্তু হওয়া উচিত operator[]একটি "প্রক্সি বস্তুর" যে যে মূল্যায়ণ এছাড়াও একটি সমর্থন operator[]

এগুলি তাদের শৃঙ্খলার একমাত্র উপায়।

বিকল্পভাবে, operator()একাধিক যুক্তি নিতে ওভারলোড , যেমন আপনি প্রার্থনা করতে পারেন myObject(x,y)


বন্ধনীগুলির ওভারলোড কেন দুটি ইনপুট পেতে দেয় তবে বন্ধনীগুলির সাহায্যে আপনি এটি করতে পারেন না?
উ। উন্মাদ

@ এফ্রেঞ্জি কারণ: ১। ২ প্যারামিটারের সাথে ওভাররাইড করার ফলে ময়বজ [২,৩] কে কল করা হবে, মায়োবজকে [২] [৩] নয়। এবং ২. অপারেটরের প্যারামগুলির সংখ্যা পরিবর্তন করা যায় না [[] অপারেটর কেবল একটি ইনট নেয়, যখন () যেকোন ধরণের পরামিতি নেয়।
বৃশ্চিক

20

দ্বি মাত্রিক অ্যারের জন্য, বিশেষত, আপনি একক অপারেটর [] ওভারলোড নিয়ে চলে যেতে পারেন যা প্রতিটি সারির প্রথম উপাদানটিতে একটি পয়েন্টার দেয়।

তারপরে আপনি সারিটির মধ্যে প্রতিটি উপাদান অ্যাক্সেস করতে অন্তর্নির্মিত ইনডেক্সিং অপারেটরটি ব্যবহার করতে পারেন।


4
আমার কাছে সবচেয়ে ব্যবহারিক এবং দক্ষ সমাধানের মতো দেখায়। কেন এটি বেশি ভোট পায় না তা ভাবুন - কারণ এটিতে চোখের কোডিং কোড নেই।
Yigal Reiss

16

আপনি যদি প্রথম [] কলটিতে কোনও ধরণের প্রক্সি ক্লাস ফিরিয়ে দেন তবে এটি সম্ভব। তবে, অন্য বিকল্প রয়েছে: আপনি অপারেটর () কে ওভারলোড করতে পারেন যে কোনও সংখ্যক আর্গুমেন্ট গ্রহণ করতে পারে ( function(3,3))।


10

একটি পদ্ধতির ব্যবহার করা হচ্ছে 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];
}

অবশ্যই, আপনি maytypedefpair<int,int>


9
এটি সি ++ 11 এবং ব্রেস সূচনা দিয়ে আরও অনেক আকর্ষণীয় হয়ে ওঠে । এখন আপনি লিখতে পারেনnValue = theArray[{2,3}];
মার্টিন বোনার

5

আপনি একটি প্রক্সি অবজেক্ট ব্যবহার করতে পারেন, এরকম কিছু:

#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;
}

4

আপনি যদি আমাকে কী function, function[x]এবং কী তা জানাতে পারেন তবে তা দুর্দান্ত হবে function[x][y]। তবে যাইহোক আমাকে এটিকে অন্য কোথাও ঘোষিত একটি বিষয় হিসাবে বিবেচনা করা উচিত let

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 টি পৃথক কল। সুতরাং প্রসঙ্গটিতে কোনও লক ব্যবহার না করা পর্যন্ত সংকলক বা রানটাইম পারমাণবিকতার গ্যারান্টি দেয় এটি শক্ত। অনুরূপ উদাহরণ হ'ল, লিবিসি বলে printfপারমাণবিক, যখন operator<<আউটপুট স্ট্রিমের ক্রমবর্ধমান ওভারলোডকে কল করা হয় না। মত একটি বিবৃতি

std::cout << "hello" << std::endl;

মাল্টি-থ্রেড অ্যাপ্লিকেশনটিতে সমস্যা থাকতে পারে তবে এর মতো কিছু

printf("%s%s", "hello", "\n");

ভাল.


2
#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;
}

2
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];
};

এটির জন্য আমার নিজের সহজ সমাধানটি খুঁজে পেয়েছি।


2
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()যা উভয় স্থানাঙ্ককে অনক্সে দুটি আর্গুমেন্ট হিসাবে পাস করতে সহায়তা করে। [][]সমর্থন সমর্থন এখন :

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);}
  );
}

এবং সম্পন্ন। কোন কাস্টম ক্লাস প্রয়োজন।


2

যদি কোনও [x] [y] না বলে আপনি একটি [{x, y}] বলতে চান তবে আপনি এটি করতে পারেন:

struct Coordinate {  int x, y; }

class Matrix {
    int** data;
    operator[](Coordinate c) {
        return data[c.y][c.x];
    }
}

1

একটি বিশেষায়িত টেম্পলেট হ্যান্ডলার ব্যবহার করে একাধিক [] ওভারলোড করা সম্ভব। এটি কীভাবে কাজ করে তা কেবল দেখানোর জন্য:

#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);
    }
};

0

একটি দিয়ে 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])));
}

সরাসরি উদাহরণ

এই সমাধানটিতে আপনাকে আসল এসটিএল ধারক সরবরাহ করার সুবিধা রয়েছে, সুতরাং আপনি লুপ, এসটিএল অ্যালগরিদম ইত্যাদির জন্য বিশেষ ব্যবহার করতে পারেন।

for (size_t i = 0; i < w; ++i)
  for (size_t j = 0; j < h; ++j)
    std::cout << *data[i][j] << std::endl;

যাইহোক, এটি পয়েন্টারগুলির ভেক্টর তৈরি করে, সুতরাং আপনি যদি এটির মতো ছোট ছোট ডেটাস্ট্রাকচার ব্যবহার করেন তবে আপনি সরাসরি অ্যারের ভিতরে থাকা সামগ্রীটি অনুলিপি করতে পারেন।


0

কোডের উদাহরণ:

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;
}

0

ভেক্টর <ভেক্টর <টি>> বা টি ** কেবল তখনই প্রয়োজন যখন আপনার ভেরিয়েবলের দৈর্ঘ্যের সারি থাকে এবং মেমরির ব্যবহার / বরাদ্দের ক্ষেত্রে যদি আপনার আয়তক্ষেত্রাকার অ্যারে প্রয়োজন হয় তার পরিবর্তে কিছু গণিত করার কথা বিবেচনা করুন! () পদ্ধতিতে দেখুন:

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; }
};

0

সি ++ 11 এবং স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে আপনি কোডের একক লাইনে খুব সুন্দর দ্বিমাত্রিক অ্যারে তৈরি করতে পারেন:

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();

এবং আপনি forআউটপুট জন্য রেঞ্জযুক্ত ব্যবহার করতে পারেন :

for (const auto &row : myMatrix) {
  for (const auto &elem : row) {
    std::cout << elem << " ";
  }
  std::cout << std::endl;
}

(অভ্যন্তরীণ arrayপ্রতিনিধিত্বকারী কলামগুলি সিদ্ধান্ত নেওয়া একটি foo[x][y]সিনট্যাক্সের অনুমতি দেয় তবে for(;;)আউটপুট প্রদর্শনের জন্য আপনাকে ক্লামিয়ার লুপ ব্যবহার করতে হবে ))


0

আমার 5 সেন্ট।

আমি স্বজ্ঞাতভাবে জানতাম আমার প্রচুর বয়লারপ্লেট কোড করা দরকার।

এজন্য অপারেটরের পরিবর্তে [], আমি ওভারলোডেড অপারেটর (ইনট, ইনট) করেছি। তারপরে চূড়ান্ত ফলাফলটিতে এম [1] [2] এর পরিবর্তে আমি এম করেছি (1,2)

আমি জানি এটি বিবিধ বিষয়, তবে এটি এখনও খুব স্বজ্ঞাত এবং গাণিতিক লিপির মতো দেখতে।


0

সবচেয়ে সংক্ষিপ্ত এবং সহজ সমাধান:

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];
  }

};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.