tags:

views:

622

answers:

5

I am writting a small piece of code exercising policy-based template programming. In this program, a CDecayer class is defined and it uses DecayerPolicy as its policy class. However the compiler complained that " expected `;' before ‘it’ " about the CDecayer part . Any suggestions?

#include <iostream>
#include <vector>
#include <map>
#include <utility>



int main()
{
}

struct CAtom
{
};

class CStateUpdater
{
public:
  virtual void UpdateState(CAtom* patom) = 0;
};


struct CDecayerPolicy
{
  typedef std::pair<unsigned int, unsigned int> indexpair;
  std::map<indexpair, double> mDecayRate;

  CDecayerPolicy()
  { 
    mDecayRate.clear();
  }

  ~CDecayerPolicy()
  {}
};



template<class DecayerPolicy>
class CDecayer: public DecayerPolicy, public CStateUpdater
{
public:
  virtual void UpdateState(CAtom* patom)
  {
    for(std::map<DecayerPolicy::indexpair, double >::const_iterator it =  DecayerPolicy::mDecayRate.begin(); it!= DecayerPolicy::mDecayRate.end(); it++)
      {
// atom state modification code
      }
  }
};
A: 

Try #include <iterator>

Michael Burr
vector includes iterators.
BipedalShark
Maybe on your implementation, but I don't think the standard mandates it.
GMan
I am using g++ 4.3.4added #include <iterator> and it doesn't work
Kuang Chen
@BipedalShark - the C++ standard permits library implementations to include other standard headers (which was not allowed in ANSI/ISO C), but doesn't require them to do so. So GMan hit the nail on the head - one compiler might include `<iterator>` while another might not. This was just a shot in the dark on my part (apparently unsuccessful).
Michael Burr
On the other hand, is it said anywhere at all that one should include <iterator> in order to use vector's and map's iterator? As far as I know, this header contains `std::iterator_traits`, std::iterator, `std::reverse_iterator`, inserters, stream iterators, and advance and distance.
UncleBens
@UncleBens - that would certainly make sense, but I'm not prepared to say that in all cases if you `#include <vector>` that you don't need to `#include <iterator>` for simple uses of the iterator typedefs in `vector<>`. I wasn't saying that a `#include <iterator>` was required, just that it might help. See http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx for a concrete example of thic kind of problem (even if it's different as the problem is with using the `back_inserter()` function from `<iterator>`).
Michael Burr
@Michael Burr: Yes, but `back_inserter()` *is* actually supposed to be defined in `<iterator>`.
UncleBens
+13  A: 

You need to add typename before dependent types, i.e.

for(typename std::map<typename DecayerPolicy::indexpair, double >::const_iterator
    it = DecayerPolicy::mDecayRate.begin();
    it != DecayerPolicy::mDecayRate.end();
    it++)
avakar
+1. Deleted my answer.
Pavel Shved
Yes it magically worked! So typename seems to be needed everywhere! Thanks.
Kuang Chen
Kuang, glad to hear it works :) Note that `typename` is not needed everywhere, only before types that depend (directly or indirectly) on a template parameter.
avakar
Avakar: Thanks, I see.
Kuang Chen
+1  A: 

You got one or two typename declarations in the wrong place:

template<class DecayerPolicy>
class CDecayer: public DecayerPolicy, public CStateUpdater
{
    public:
        virtual void UpdateState(CAtom* patom)
        {
            typedef typename DecayerPolicy::indexpair     indexpair;
            typedef typename std::map<indexpair, double>  mymap;
            typedef typename mymap::const_iterator        const_iterator;
            //
            for(const_iterator it = DecayerPolicy::mDecayRate.begin();
                it!= DecayerPolicy::mDecayRate.end();
                it++)
            {
                // atom state modification code
            }
        }
};

Though personally I would do this:

template<class DecayerPolicy>
class CDecayer: public DecayerPolicy, public CStateUpdater
{
    typedef typename DecayerPolicy::indexpair     indexpair;
    typedef typename std::map<indexpair, double>  mymap;
    typedef typename mymap::const_iterator        const_iterator;
    typedef typename mymap::value_type            value_type;
    //
    struct AtomStateModifier
    {
        void operator()(value_type const& data) const
        {
        }
    };
    //
    public:
        virtual void UpdateState(CAtom* patom)
        {
            std::for_each(DecayerPolicy::mDecayRate.begin(),
                          DecayerPolicy::mDecayRate.end(),
                            AtomStateModifier()
                         );
        }
};
Martin York
The second `typename` is unnecessary.
avakar
Yes. But it makes it look neat. And neat is maintainable.
Martin York
A: 

The below appears to work. indexpair map isnt actually using any template types..?

typedef std::map<std::pair<unsigned int, unsigned int>, double>  indexpairmap;
struct CDecayerPolicy
{
   indexpairmap mDecayRate;
   CDecayerPolicy()
   {
     mDecayRate.clear();
   }

   ~CDecayerPolicy()
   {}
};



template<class DecayerPolicy>
class CDecayer: public DecayerPolicy, public CStateUpdater
{
public:
  virtual void UpdateState(CAtom* patom)
  {
    indexpairmap::iterator it =  DecayerPolicy::mDecayRate.begin();
    for(; it!= DecayerPolicy::mDecayRate.end(); it++)
      {
      // atom state modification code
      }
  }
};
sean riley
Sean: Yes, it will work if you reference iterator that way. Since my goal is to make the CDecayer need information from its base class, I tend not to supply iterator information from outside.
Kuang Chen
+1  A: 

I've examined and modified your code (hopefully improving it lol). Works for me.

#include <iostream>
#include <map> // map contains <utility>


using namespace std;

struct CAtom
{
};

class CStateUpdater
{
public:
  virtual void UpdateState(CAtom* patom) = 0;
}; // CStateUpdater

typedef std::pair<unsigned int, unsigned int> indexpair;
typedef std::map<indexpair, double> decay_map;
typedef decay_map::const_iterator decay_map_citerator;


class CDecayerPolicy
{
 public :
  CDecayerPolicy() { mDecayRate.clear(); }
  ~CDecayerPolicy() {}

  const decay_map & getDecayRate() const { return mDecayRate; }
  void setDecayRate(const decay_map & d_m) { mDecayRate = d_m; }
 private :
  decay_map mDecayRate;
};


template<class T> class CDecayer: public CStateUpdater
{
 public:
  CDecayer(const T & data) { policy = data; }
  virtual void UpdateState(CAtom* patom)
  {
   for(decay_map_citerator it = policy.getDecayRate().begin(); it != policy.getDecayRate().end(); ++it)
   {
    // atom state modification code
    cout << "[ "
     << it->first.first 
     << " , "
     << it->first.second 
     << " ] : "
     << it->second << endl;
   }
  }
 private :
  T policy;
};

int main()
{
 const indexpair idx_p1 = indexpair(1, 5);
 const indexpair idx_p2 = indexpair(2, 4);
 const indexpair idx_p3 = indexpair(3, 3);
 const indexpair idx_p4 = indexpair(4, 2);
 const indexpair idx_p5 = indexpair(5, 1);

 decay_map the_decay_map;
 the_decay_map[idx_p1] = 3.0;
 the_decay_map[idx_p2] = 5.2;
 the_decay_map[idx_p3] = 6.4;
 the_decay_map[idx_p4] = 1.4;
 the_decay_map[idx_p5] = 6.5;

 CDecayerPolicy the_policy;
 the_policy.setDecayRate(the_decay_map);

 CDecayer<CDecayerPolicy> the_decayer(the_policy);
 the_decayer.UpdateState(NULL);

 return 0;
}
Maciek
Maciek: Thanks for your comment, which provide another nice way of policy-based design. :)
Kuang Chen
No problem, glad to be of help
Maciek