HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Using a template to cycle through a sequence of containers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cycletemplatesequenceusingthroughcontainers

Problem

I'm trying to implement a template that takes a container as parameter. The template has a getnext method that cycles through the elements in the parameter. Take note that I'm not using C++11.

Header:

#pragma once

template class TContainer, class TObject>
class cycle
{
public:

    explicit cycle( TContainer> & container )
        : mContainer( container ), index(0) {}

    TObject getNext(int numObjectsToCycle) 
    { return mContainer[index++ % numObjectsToCycle]; }
private:
    TContainer> & mContainer;
    int index;
};


Implementation:

#include 
#include 

#include "cycle.h"

using namespace std;

class Processor
{
   int mIndex;
   vector numbers;

public:
   cycle cycler;
   // Is it safe to pass numbers since it is declared first??
   Processor() : mIndex(0), cycler(numbers) {} 
   void update() { cout << numbers[mIndex++ % numbers.size()] << std::endl;}
   void addNumber(int x) { numbers.push_back(x); }
};

int main()
{
   Processor S;

   for (int i = 0; i < 5; ++i)
   {
      S.addNumber(i+1);
   }
   cout << "using update" << endl;
   for (int c = 0; c < 10; ++c)
   {
      S.update();
   }

   cout << "using cycle" << endl;
   for (int c = 0; c < 10; ++c)
   {
      cout << S.cycler.getNext(5) << endl;
   }

   std::cin.get();

}


Any improvement or potential issues to the code?

Solution

Here is how I would write it:

template
class cycle
{
    C& mContainer;
    size_t index;
    using ref = decltype(mContainer[0]);

public:
    explicit cycle(C& container) :
        mContainer(container), index(0) {}

    ref getNext()
    {
        return mContainer[index++ % mContainer.size()];
    }
};


Notes:

-
The template parameter is the container, C. This not only simplifies code, but also works for containers that do not follow a specific pattern, e.g. have more parameters than just a value type and an allocator type.

-
The return type of getNext is automatically inferred from C. This is not just C's value_type but a (non-const) reference to it.

-
If I understand correctly from the title, C is supposed to be a sequence of containers? If so, the value_type is a container itself so it is even more important that a reference is returned from getNext.

-
Why pass a parameter to getNext? To cycle correctly, you should use mContainer.size(), exactly as you do in Processor::update, right?

-
index is of type size_t

With only a few changes, here is Processor:

class Processor
{
   size_t mIndex;
   std::vector numbers;

public:
   cycle> cycler;
   Processor() : mIndex(0), numbers(), cycler(numbers) {}
   void update() { std::cout << numbers[mIndex++ % numbers.size()] << std::endl;}
   void addNumber(int x) { numbers.push_back(x); }
};


Notes:

  • again, mIndex is a size_t



  • cycler is a cycle



  • numbers is default-initialized



  • cycler is safely constructed after numbers



Also, whenever you want to

using namespace std;


for convenience, only do it inside another (your own) namespace, never globally.

EDIT

I just noticed you're not using C++11. In this case, just use

typedef typename C::value_type& ref;


instead.

Code Snippets

template<typename C>
class cycle
{
    C& mContainer;
    size_t index;
    using ref = decltype(mContainer[0]);

public:
    explicit cycle(C& container) :
        mContainer(container), index(0) {}

    ref getNext()
    {
        return mContainer[index++ % mContainer.size()];
    }
};
class Processor
{
   size_t mIndex;
   std::vector<int> numbers;

public:
   cycle<std::vector<int>> cycler;
   Processor() : mIndex(0), numbers(), cycler(numbers) {}
   void update() { std::cout << numbers[mIndex++ % numbers.size()] << std::endl;}
   void addNumber(int x) { numbers.push_back(x); }
};
using namespace std;
typedef typename C::value_type& ref;

Context

StackExchange Code Review Q#48110, answer score: 3

Revisions (0)

No revisions yet.