Solved

Functor Template Within Another Template

Posted on 2012-03-10
22
666 Views
Last Modified: 2012-08-14
I have written a wrapper class around the std::list template.
I have not inherited from the std::list for many reasons; one of them being it has no virtual destructor.
My reasons for doing this are valid, and I will not go into them here.
However, I have hit a problem:
My class is defined as

template<class TYPE>
class List
{
public:
        template<class TYPE, typename PARAMETER>
        class FindFunctor
        {
        public:
            FindFunctor( PARAMETER p1 ) : m_value( p1 ){}
            virtual bool operator()( TYPE& t1 ) = 0;

        protected:
            PARAMETER m_value;
        };

public:
    List(void){};
    virtual ~List(void){};
    ...
    inline bool IsEmpty(void) { return m_list.empty(); }
    ...

    template <class TYPE, typename PARAMETER>
    bool FindElement( FindFunctor<TYPE, PARAMETER>, std::list::iter pos )
    {
        ...
        pos = std::find_if( m_list.begin(), m_list.end(), FindFunctor );
        return true; // for the sake of degugging
    }
   
private:
    std::list<TYPE> m_list;
};

The method FindElement exposes the find_if( first, last, Pred ) function and I need to provide prototype declaration for the functor, which needs to be parameterised, and so is templated, as can be seen above as a nested class.

In my code I have declared a class thus:

List<SomeObject> myList;
typedef typename std::list<SomeObject::iterator ListIndex;

class DerivedFindFunctor : public List<SomeObject>::FindFunctor<SomeObject, int>
{
public:
    DerivedFindFunctor( int p1 ) : List<SomeObject>::FindFunctor<SomeObject, int>( p1 ){}
    bool operator()( SomeObject& item ) { return item->GetCount() == m_value; }
};

and I use it in my code, thus:

myList.FindElement( DerivedFindFunctor( 10 ), ListIndex& pos );

However, I get a compiler error.
"error C2784..... could not deduce template argument for 'List<TYPE>::FindFunctor<TYPE, PARAMETER>' from DerivedFindFunctor

Any help in rresolving this issue would be appreciated. Thanks.
0
Comment
Question by:Orcbighter
  • 12
  • 10
22 Comments
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
>> I have not inherited from the std::list for many reasons; one of them being it has no virtual destructor.
An that is exactly right - it is generally considered bad practice to derive from the STL classes and there is rarely a good reason to consider doing so.

Can you post an actual buildable example please. It's always a lot simpler to see what's wrong when you can build it yourself :)
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Here you go - the code example you posted modified so it builds. The basic issue was you were shadowing the template type TYPE in the FindFunctor. Since TYPE is already defined by the containing class there is no need to define it again unless you expect it to be a different type that that of the containing class. In that case you need to call it something other than TYPE as the name is already in use in that scope.


#include <list>
#include <algorithm>

template<class TYPE>
class List
{
   public:
      template<typename PARAMETER>
         class FindFunctor
         {
            public:
               FindFunctor( PARAMETER p1 ) : m_value( p1 ){}
               virtual bool operator()( TYPE& t1 ) = 0;

            protected:
               PARAMETER m_value;
         };

   public:
      List(void){};
      virtual ~List(void){};
      inline bool IsEmpty(void) { return m_list.empty(); }

      template <typename PARAMETER>
      bool FindElement( FindFunctor<PARAMETER>, typename std::list<TYPE>::iterator pos )
      {
         pos = std::find_if( m_list.begin(), m_list.end(), FindFunctor<PARAMETER>() );
         return true; // for the sake of degugging
      }

   private:
      std::list<TYPE> m_list;
};

struct SomeObject{ int GetCount() const {return 0;} };

int main()
{
   List<SomeObject> myList;
   typedef typename std::list<SomeObject>::iterator ListIndex;

   class DerivedFindFunctor : public List<SomeObject>::FindFunctor<int>
   {
      public:
         DerivedFindFunctor( int p1 ) : List<SomeObject>::FindFunctor<int>( p1 ){}
         bool operator()( SomeObject& item ) { return item.GetCount() == m_value; }
   };
}

Open in new window


Let me know if there is anything you need explaining.
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
Thanks evilrix,
I implementated those changes, however, when I add the line of code missed from your response, ie.

Listr<SomeObject>::iterator pos;

bool OK = myList.FindItem( DerivedFindFunctor( 10 ),  pos );

I get a new form of the same error message, ie:
"error C2784..... could not deduce template argument for 'List<TYPE>::FindFunctor<PARAMETER>' from DerivedFindFunctor
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Ok, my first post just focused on trying to fix up some of the compiler errors. In truth; however, the code is far more complex than it really needs to be. You don't need a virtual base for your predicate (in fact, if you add an operator == and operator < to SomeObject you don't even need the predicate but you'll be able to make use of the standard predicates should you need to perform different tests).

Anyway, below is the code, refactored. Let me know if you need anything explaining. Shortly I'll post how I'd do this so you can see just how simple this code could be.

#include <list>
#include <algorithm>

template<class TYPE>
class List
{
   public:
      typedef typename std::list<TYPE>::iterator iterator;
      typedef typename std::list<TYPE>::const_iterator const_iterator;

   public:
      inline bool IsEmpty() const { return m_list.empty(); }

      template <typename Predicate>
      bool FindElement( Predicate pred, iterator & pos )
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

      template <typename Predicate>
      bool FindElement( Predicate pred, const_iterator & pos ) const
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

   private:
      std::list<TYPE> m_list;
};

struct SomeObject
{
   int GetCount() const {return 0;}

};

class FindFunctor
{
   public:
      FindFunctor( int p1 ) : m_value(p1) {}
      bool operator()( SomeObject const & item ) const
      {
         return item.GetCount() == m_value;
      }

   private:
      int m_value;
};

int main()
{
   List<SomeObject> myList;
   List<SomeObject>::iterator pos;

   bool OK = myList.FindElement( FindFunctor( 10 ),  pos );
}

Open in new window

0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
Thanks evilrix,
but you missed the point of the problem.
I have created a template for a list of some TYPE. The Functor is used to compare each element in the list of TYPES and return true when the comparison finds a match.
By not making the functor a template, you are forcing it to use an integer in the comparison, which is an invalid assumption. What if the object contains strings, and other complex objects? You would need the predicate to take the relevant data type for use in the comparison.
Hence the need to template the functor.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
>>but you missed the point of the problem.

Not really :)

The problem is your code (the predicate) is too specific. It is a trivial change to make it template to test any type but the fact that it calls GetCount() means it can never be a generic solution.

FWIW, this should do what you want:

#include <list>
#include <algorithm>

template<class TYPE>
class List
{
   public:
      typedef typename std::list<TYPE>::iterator iterator;
      typedef typename std::list<TYPE>::const_iterator const_iterator;

   public:
      inline bool IsEmpty() const { return m_list.empty(); }

      template <typename Predicate>
      bool FindElement( Predicate pred, iterator & pos )
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

      template <typename Predicate>
      bool FindElement( Predicate pred, const_iterator & pos ) const
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

   private:
      std::list<TYPE> m_list;
};

struct SomeObject
{
   int GetCount() const {return 0;}

};

template <typename T> // <--- it's templated :)
class FindFunctor
{
   public:
      FindFunctor( T const & p1 ) : m_value(p1) {}

      template <typename U>
      bool operator()(U const & item ) const
      {
         return item.GetCount() == m_value;
      }

   private:
      T m_value;
};

int main()
{
   List<SomeObject> myList;
   List<SomeObject>::iterator pos;

   bool OK = myList.FindElement( FindFunctor<int>( 10 ),  pos );
}

Open in new window

0
 
LVL 40

Accepted Solution

by:
evilrix earned 500 total points
Comment Utility
This is a far more genetic way to do what you're trying to do. Again, if anything is not clear just ask.

#include <list>
#include <algorithm>
#include <functional> // for bind1st and equal

using namespace std;

template<class TYPE>
class List
{
   public:
      typedef typename std::list<TYPE>::iterator iterator;
      typedef typename std::list<TYPE>::const_iterator const_iterator;

   public:
      inline bool IsEmpty() const { return m_list.empty(); }

      template <typename Predicate>
      bool FindElement(Predicate pred, iterator & pos )
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

      template <typename Predicate>
      bool FindElement(Predicate pred, const_iterator & pos ) const
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

   private:
      std::list<TYPE> m_list;
};

struct SomeObject
{
   int GetCount() const {return 0;}
};

template <
   typename T, // this is the value type
   template <typename> class P, // this is a template template type
   typename U // this is the class type we are supporting
   >
class FindFunctor
{
   public:
      typedef const_mem_fun_ref_t<T, U> func_t;

      FindFunctor(
            T const & p1, // the value we wish to match
            func_t const & func // a functor that will get value from item
            )
         : m_value(p1)
         , m_func(func) {}

      bool operator()(U const & item ) const
      {
         return P<T>()( // create a predicate and call it
               m_func(item), // call the member function on item to get value
               m_value); // and compare it with my value
      }

   private:
      T m_value; // the value to match
      func_t m_func; // the function to get that value
};

int main()
{
   List<SomeObject> myList;
   List<SomeObject>::iterator pos;

   FindFunctor<
      int, // value type
      equal_to, // predicate type
      SomeObject // object type we're getting value from
   >
   pred(10, mem_fun_ref(&SomeObject::GetCount));

   myList.FindElement(pred, pos);
}

Open in new window

0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
And, just for the sake of interest. This is how simple the code could be were you to use Boost bind.
http://www.boost.org/doc/libs/1_49_0/libs/bind/bind.html

#include <list>
#include <algorithm>
#include <functional> // for bind1st and equal
#include <boost/bind.hpp>

using namespace std;

template<class TYPE>
class List
{
   public:
      typedef typename std::list<TYPE>::iterator iterator;
      typedef typename std::list<TYPE>::const_iterator const_iterator;

   public:
      inline bool IsEmpty() const { return m_list.empty(); }

      template <typename Predicate>
      bool FindElement(Predicate pred, iterator & pos )
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

      template <typename Predicate>
      bool FindElement(Predicate pred, const_iterator & pos ) const
      {
         pos = std::find_if( m_list.begin(), m_list.end(), pred );
         return pos != m_list.end();
      }

   private:
      std::list<TYPE> m_list;
};

struct SomeObject
{
   int GetCount() const {return 0;}
};

int main()
{
   List<SomeObject> myList;
   List<SomeObject>::iterator pos;

   myList.FindElement(boost::bind(equal_to<int>(), 10,
            bind(&SomeObject::GetCount, _1)), pos);
}

Open in new window

0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
OK, evilrix.
You cannot see where you are wrong. I will try again.

Your criticism about my solution being too specific and quoting the GetCount method is wrong.
You are criticising your modifications to my code. I never wrote that!
My template List class is a generic solution, which means I have to supply a generic FindFunctor to be used within that class.
This I did by creating a template for it, and by making it abstract (the overloaded operator() is a pure virtual function.

The specific GetCount() method was used in a Derived class, outside the List files, in my application where I had instantiated the abstract class and provided an overloaded() operator specific to my needs.
My problem is in finding the correct syntax for this solution so that my code will compile. It was a a generic solution.

Another programmer, using my List template might, for example used to contain Porridge objects where there are no ints.

class Brand
{
public:
    ...
};

class Porridge
{
public:
    Porridge( const string& name,
   
    string GetDescription() { return m_name; };
   
private:
        string m_name;
        float m_quantity;
        Brand m_brand;
};

List<Porridge> m_list;

// the derived FindFunctor
class DerivedFindFunctor : public List<Porridge>::FindFunctor<Porridge, string>
{
public:
    DerivedFindFunctor( string str1 ) : List<Porridge>::FindFunctor<Porridge, string>( str1 ){}
    bool operator()( Porridge& item ) { return item->GetDescription().compare( m_value) == 0; }
};

So you see, my List class ( in the file List.h ) will be used by others who will derived from the generic definition of FindFunctor within that file. The derived class will be in their application, and they will write the overloaded operator() method to suit their class of objects (in this case Porridge objects).
And as for Boost, well I have nothing against them, but it is a lazy option, and I see no need to suck in third-party libraries to do a job that I should be able to do myself (with a little help from Experts Exchange :-) )
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
Hi evilrix,
Well, "write in haste, repent at leisure", so the saying goes. I have to give you a mia culpa.
I went back over your last entry and implemented it, with a few changes, and it worked!

Thank you.
0
 
LVL 9

Author Closing Comment

by:Orcbighter
Comment Utility
The solution was successful.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Heh. No worries. I'm glad I was able to help you.

Please do post back here if you have any further queries or need any help refining this.

Best of luck.
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
Hi evilrix,
I will take you up on your offer of answering further queries.
I have modified the list so that it takes pointers to objects where those pointers are wrapped in a share_ptr.

template<class TYPE>
class List
{
   public:
      typedef tr1::shared_ptr<TYPE> ItemPtr;
      typedef typename std::list<TYPE>::iterator iterator;
...

    template<typename PREDICATE>
    inline bool FindItem( PREDICATE pred, ItemPtr& item, ListIndex& pos );

....

    private:  // member variables
        list<ItemPtr> m_list;
};

the functor declaration is unchanged

and in my code

    SList_Ptr<DummyClass> myList;
    SList_Ptr<DummyClass>::ListIndex pos;      
    SList_Ptr<DummyClass>::ItemPtr item;

    FindFunctor<unsigned long, equal_to, SList_Ptr<DummyClass>::ItemPtr>  pred( 10, mem_fun_ref( &SList_Ptr<DummyClass>::ItemPtr::GetCount ));           // <<-- error on this line
       
    bool bOK = myList.FindItem( findPred, item, pos );

I get the following error:    
Error      1      error C2039: 'GetCount' : is not a member of 'std::tr1::shared_ptr<_Ty>'
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
On that line you're asserting that shared_ptr<TYPE> has a member called GetCount and, clearly, it doesn't.

Try chaning it to this:

 FindFunctor<unsigned long, equal_to, SList_Ptr<DummyClass>::ItemPtr>  pred( 10, mem_fun_ref( &DummyClass::GetCount ));           // <<-- error on this line

I presume that you want to call GetCount on DummyClass. The fact it's bound with shared_ptr<DummyClass> makes no difference as it'll still get called listPtr->DummyClass().
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
Tried that. Got this:
Error      1      error C2664: 'MWG::FindFunctor<T,P,U>::FindFunctor(const T &,std::mem_fun_ref_t<_Result,_Ty> &)' : cannot convert parameter 2 from 'std::mem_fun_ref_t<_Result,_Ty>' to 'std::mem_fun_ref_t<_Result,_Ty> &'
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Try changing std::mem_fun_ref_t<_Result,_Ty> & to be std::mem_fun_ref_t<_Result,_Ty> const &. Because you're creating the mem_fun_ref_t in-line with the call it's a temporary and, thus, considered an R-Value not an L-Value.
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
I am not sure what you mean.
If I change the typedef within the FindFunctor class, currently:
        typedef mem_fun_ref_t<T, U> func_t;
to
    typedef mem_fun_ref_t<T, U> const & func_t;

I get the compiler error:
         Error      1      error C2529: 'func' : reference to reference is illegal
Sorry to be  a bit slow on this stuff.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
It's the function definition you need to change.

FindFunctor(const T &,std::mem_fun_ref_t<_Result,_Ty> &)

to

FindFunctor(const T &,std::mem_fun_ref_t<_Result,_Ty> const &)
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
typedef mem_fun_ref_t<T, U> func_t;
   
FindFunctor( T const& p1, // the value we wish to match
                 func_t const& func ) // a functor that will get value from item
                 //func_t& func ) // a functor that will get value from item
      : m_value( p1 ),
        m_func( func ) {}

commented out part shows the change I made
The error is now
Error      1      error C2664: 'FindFunctor<T,P,U>::FindFunctor(const T &,const std::mem_fun_ref_t<_Result,_Ty> &)' : cannot convert parameter 2 from 'std::const_mem_fun_ref_t<_Result,_Ty>' to 'const std::mem_fun_ref_t<_Result,_Ty> &'
List.h
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
You seem to have some const-correctness issues going on. Can you post me the whole code as it'll be easier for me to figure out what's going on?
0
 
LVL 9

Author Comment

by:Orcbighter
Comment Utility
I have zipped up my Visual Studio project for you, but I had to rename some of the files for the attacher not to object.
I added the file extension "_.txt" to each of the files that were causing problems (it was the project files and the inline file for the template.
Just remove the "_.txt" file extension and it should all compile and work
This is a Visual Studio 2008 project.
ListPtrTesterForEE.zip
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Sorry, I ended up going to bed last night before your update. I'll take a look at this sometime later today and get back to you. I've had an initial glance and I think the issue is that you're gonna need to do a partial specialisation of FindFunctor for shared_ptr types. The reason is that FindFunctor is getting confused between DummyClass and shared_ptr<DummyClass>. This is just my gut instinct though; I've yet to try and do anything to test and fix the code.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Okay. So what exactly is the problem here? How often have we come across situations where we need to know if two strings are 'similar' but not necessarily the same? I have, plenty of times. Until recently, I thought any functionality like that wo…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now