Klasa tablicy numerowanej od dowolnego indeksu, propozycje

Odpowiedz Nowy wątek
2011-09-05 13:48
0

Witam, jako że często w tematach dla Newbie zauważyłem potrzebę użycia tablicy o stałym rozmiarze jednak nie numerowanej od zera postanowiłem taką napisać i przy okazji poduczyć się nowego standardu C++11. Chciałem, żebyście powiedzieli co by tu można dodać zmienić itd. żeby użycie jej było wygodne i szybkie (nie jestem pewien czy lambdy nie spowalniają kodu)

#include <functional>
#include <assert.h>
 
using namespace std;
 
template<typename T, int N, int FROM = 0>
class array
{
public:
  typedef function<void(int,T&)>(ElementFunction);
  array()
    {
      _tab = _tab_ - FROM;
    }
  array(const T& value)
    {
      _tab = _tab_ - FROM;
      each([&value](const int index,T& el){el = value;});
    }
  T& operator[] (const int index)
    {
      assert(index>=FROM && index<FROM+N);
      return _tab[index];
    }
  array<T,N,FROM>& operator= (const array<T,N,FROM>& x)
    {
      each([&](const int i,T& el){el = x[i];});
    }
  void each(ElementFunction func)
    {
      for (int i=FROM,TO = FROM+N; i<TO; ++i)
        func(i,_tab[i]);
    }
private:
  T _tab_[N];
  T* _tab;
};

przykład użycia (wymienia ile liczb z zakresu od <-5..5> podał użytkownik):

int main()
{
  array<int, 11, -5> a;
 
  int d;
  while (cin >> d)
    {
      a[d]++;
      a.each([&](const int i, int& el){cout << i << ": " << el << endl;});
      cout << endl;
    }
  return 0;
}

░█░█░█░█░█░█░█░█░█░█░█░
edytowany 1x, ostatnio: krwq, 2011-09-05 13:50
aktualny kod jest niżej. z jakiegoś nieznanego powodu nie mogę edytować posta - krwq 2011-09-05 15:47

Pozostało 580 znaków

2011-09-05 14:14
1

nie jestem pewien czy lambdy nie spowalniają kodu

wszystko może spowolnić, jeśli kompilator jest słaby. na przykład: czy optymalizator pozwala na inline'owanie lambd? może nie musi. pamiętaj że wszelkie nowe cuda, w tym lambdy, są normalnie kompilowane do natywnego kodu, tak jak zawsze.

template<typename T, int N, int FROM = 0>

chyba bardziej intuicyjne byłoby template<typename T, int FROM, int TO>, choć wtedy nie możesz użyć parametru domyślnego.

each([&value](const int index,T& el){el = value;});

hmm... bardziej standardowo byłoby oprogramować iteratory begin() i end(), wtedy można będzie użyć pętli "range based for":

array<int, 10, 1> tablica;
for (int &el : tablica)
{
   cout << el << endl;
}

dodaj też funkcję size().

edytowany 3x, ostatnio: Azarien, 2011-09-05 14:16

Pozostało 580 znaków

2011-09-05 14:29
0

Lambdy to po prostu obiekty funkcyjne, w sumie to tylko lukier składniowy.

Zasady "inlineowania" są pewnie takie same jak w innych przypadkach - jeżeli kompilator uzna, że ma to sens, to tak zrobi.


"(...) otherwise, the behavior is undefined".
proponuję użyć metody Stalina: „wierzę, ale sprawdzam” - Azarien 2011-09-05 16:23

Pozostało 580 znaków

2011-09-05 15:41
0

Poza poprawką <T,FROM,TO> dodałem chyba wszystko to co napisał @Azarien:

#include <iostream>
#include <functional>
#include <assert.h>
 
using namespace std;
 
template<typename T, int N = 0, int FROM = 0>
class array
{
public:
  typedef function<void(int,T&)>(ElementFunction);
  typedef T* iterator;
  array(): _tab(_tab_ - FROM), _begin(_tab_), _end(_tab_+N)
    {
    }
  array(const T& value): _tab(_tab_ - FROM), _begin(_tab_), _end(_tab_+N)
    {
      each([&value](const int index,T& el){el = value;});
    }
  T& operator[] (const int index)
    {
      assert(index>=FROM && index<FROM+N);
      return _tab[index];
    }
  array<T,N,FROM>& operator= (const array<T,N,FROM>& x)
    {
      for (iterator i=begin(),j=x.begin(); i!=end() && j!=end(); ++i,++j)
        *i=*j;
    }
  void each(ElementFunction func, iterator itbegin, iterator itend)
    {
      for (iterator i = itbegin; i!=itend; ++i)
        func((int)(i-_begin),*i);
    }
  void each(ElementFunction func, iterator itbegin)
    {
      each(func,itbegin,_end);
    }
  void each(ElementFunction func)
    {
      each(func,_begin,_end);
    }
  int size() const
    {
      return N;
    }
  iterator begin() const
    {
      return _begin;
    }
  iterator end() const
    {
      return _end;
    }
private:
  T _tab_[N];
  T* const _tab;
  const iterator _begin;
  const iterator _end;
};
 
int main()
{
  array<int, 11, -5> a(0);
 
  /* wczytywanie danych */
  int d;
  while (cin >> d)
    {
      if (d<-5 || d>5)
        break;
      a[d]++;
      a.each([&](const int i, int& el){cout << i << ": " << el << endl;});
      cout << endl;
    }
 
  /* test operatora= */
  decltype(a) b;
  b=a;
 
  /* iteratory */
  cout << b[0];
  for (array<int>::iterator /*lub auto lub decltype(a)*/ i = b.begin()+1; i!=b.end(); ++i)
     cout << ", " << *i;
  cout << endl;
 
  /* indeksy */
  for (int i = 5; i>=-5; --i)
     cout << "b[" << i << "]=" << b[i] << endl;
  return 0;
}

░█░█░█░█░█░█░█░█░█░█░█░
możesz zrobić jeszcze const_iterator - Azarien 2011-09-05 16:25

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0