11. Eltolt indexelésű tömb

Czirkos Zoltán · 2019.02.27.

Régebbi ZH feladat megoldása.

a) Készítsen adapter sablont (Indexelheto), ami minden indexelhető (operator[]) szabványos sorozattárolóra alkalmazható és segítségével egy M elemet tartalmazó tároló első eleme N, a második eleme N+1, harmadik N+2 ... N+M-1 indexértékkel érhető el, ahol N, és M tetszőleges egész. Alapértelmezésként N = 0, a tároló pedig az std::vector legyen! A sorozattároló minden tagfüggvénye legyen elérhető, kivéve az at()! Ügyeljen a sorozattárolókra jellemző konstruktorok megvalósítására is! Példa a használatra:

Indexelheto<int, 10> v10(2); // 10-től indexelhető 2 elemű vektor
v10[10] = 1; // első eleme 1
v10[11] = 2; // második eleme 2

b) Hozzon létre az elkészített adapter és az std::deque felhasználásával egy 20-tól indexelhető 30 elemű egész tömböt!

c) Írjon C++ függvénysablont (keres), ami egy iterátorokkal megadott adatsorozatban megkeresi az első olyan elemet, amire az adott predikátum igaz értéket ad!

A függvény első két paramétere két iterátor, amivel a szokásos módon megadjuk a jobbról nyílt intervallumot. A függvény 3. paramétere pedig egy predikátum, ami egy egyparaméteres függvény vagy függvényobjektum. Amennyiben nincs a feltételnek megfelelő elem, akkor az adatsorozat végét jelző értékkel (iterátor) térjen vissza a függvény!

Ha jól oldja meg a feladatot, akkor az alábbi kódrészlet lefutása után az eredmény a 3-as indexű elemre (-16) fog mutatni.

bool negativ(int a) { return a < 0; }
int sorozat[] = { 1, 4, 9, -16, 25, 0, 72, 100, 0 };
int *eredmeny = keres(sorozat, sorozat+9, negativ);

d) Készítsen olyan függvényobjektum sablont, ami a keres sablonnal felhasználható az olyan elemek megkeresésére, amelyek nagyobbak a függvényobjektum konstruktorában megadott értéknél!

e) A részfeladatok eredményeit felhasználva írjon kódrészletet, ami a b) részfeladatban létrehozott tömbből kiírja a szabványos kimenetre az első 26-nál nagyobb értéket! (Feltételezheti, hogy van ilyen.)

#include <iostream>
#include <vector>
#include <deque>


template <typename T, int N = 0, typename TAROLO = std::vector<T>>
class Indexelheto : public TAROLO {
  private:
    T & at(size_t idx);
    T const & at(size_t idx) const;
  public:
    Indexelheto(size_t meret = 0, T adat = T()) : TAROLO(meret, adat) {}
    template <typename ITERATOR>
    Indexelheto(ITERATOR begin, ITERATOR end) : TAROLO(begin, end) {}

    T & operator[](int idx) { return TAROLO::operator[](idx-N); }
    T const & operator[](int idx) const { return TAROLO::operator[](idx-N); }
};

/*
Megj. ez nem tökéletes megoldás igazából, mert sérti az OOP egyik alapelvét.
A "minden függvénye elérhető, kivéve az at()" igazából NEM öröklési viszony.
Ha a madarak tudnak repülni, akkor a strucc nem madár. Ha fogunk egy
std::vector<int> referenciát, és ráállítjuk egy Indexelheto<int>-re, akkor
simán meghívható azon keresztül az at()... Ahogy az indexet nem eltoló
operator[] is, mivel az sem virtuális az std::vectorban. Privát öröklést
kellene csinálni, de akkor meg using-olni kell egyesével az összes tagfüggvényt.
*/


template <typename ITER, typename PRED>
ITER keres(ITER begin, ITER end, PRED p) {
    for (ITER it = begin; it != end; ++it) {
        if (p(*it))
            return it;
    }
    return end;
}


template <typename T>
class Nagyobb {
    private:
        T minel;
    public:
        Nagyobb(T minel = T()) : minel(minel) {}
        bool operator() (T mi) const {
            return mi > minel;
        }
};


bool negativ(int a) {
    return a < 0;
}


int main() {
    int sorozat[] = { 1, 4, 9, -16, 25, 0, 72, 100, 0};
    int *eredmeny = keres(sorozat, sorozat+9, negativ);
    std::cout << *eredmeny << std::endl;

    Indexelheto<int, 10, std::deque<int>> d(sorozat, sorozat+9);

    std::cout << *keres(d.begin(), d.end(), Nagyobb<int>(26)) << std::endl;

    return 0;
}