C ++ Templated Functor (based on Modern C ++ Design) will compile an error

Based on Chapter 5 (Generalized Functors) from the book "C ++ Modern Design,"

I am trying to write a Functor template. Before you ask me: "Why don't I just use Boost bind or Loki directly?" the simple answer is "because I want to learn."

Having said that, I followed this book and also used the example code as a reference, but I continue with compilation errors and I cannot understand why.

When I change the code for an example book to not use streaming models, the examples work fine. But my code does not do this. Here is the relevant code:

very simple TypeList, along with TypeAt and Nulltype, EmptyType (also based on the book)

<TypeList.hpp> --- class NullType {}; class EmptyType {}; #define TYPELIST_1(T1) TypeList<T1, NullType> #define TYPELIST_2(T1,T2) TypeList<T1, TYPELIST_1(T2) > #define TYPELIST_3(T1,T2,T3) TypeList<T1, TYPELIST_2(T2, T3) > template < typename T, typename U > struct TypeList { typedef T Head; typedef U Tail; }; namespace typelist { template <class TList, unsigned int i > struct TypeAt; template <class Head, class Tail > struct TypeAt<TypeList<Head, Tail>,0 > { typedef Head Result; }; template <class Head, class Tail, unsigned int i > struct TypeAt<TypeList<Head, Tail>, i > { typedef typename TypeAt<Tail, i-1>::Result Result; }; template <class TList, unsigned int index, typename DefaultType = NullType> struct TypeAtNonStrict { typedef DefaultType Result; }; } --- 

Using this of course functor

 <Functor.hpp> --- namespace functorPrivate { template<typename R> struct FunctorBase { typedef R ResultType; typedef EmptyType Param1; private: }; } template <typename R, class TList> class FunctorImpl; template <typename R> class FunctorImpl<R, NullType > : public functorPrivate::FunctorBase<R> { public: typedef R ResultType; virtual ~FunctorImpl(){} virtual R apply() = 0; }; template <typename R, typename P1> class FunctorImpl<R, TYPELIST_1(P1) > : public functorPrivate::FunctorBase<R> { public: typedef R ResultType; typedef P1 Param1; virtual ~FunctorImpl(){} virtual R apply(P1) = 0; }; template < class ParentFunctor, typename Fun> class FunctionHandler : public ParentFunctor::Impl { private: typedef typename ParentFunctor::Impl Base; Fun fun; public: typedef typename Base::ResultType ResultType; typedef typename Base::Param1 Param1; FunctionHandler(const Fun& fun) : fun(fun) {} virtual ~FunctionHandler() {} virtual ResultType apply() { return fun(); } virtual ResultType apply(Param1 p1) { return fun(p1); } }; template <typename R, class TList = NullType> class Functor { public: typedef TList ParamList; typedef R ResultType; typedef FunctorImpl<R, TList> Impl; typedef typename Impl::Param1 Param1; Functor() : impl(0) {} //Function / Handling functor type templated constructor template<class Fun> Functor(const Fun& fun) : impl(new FunctionHandler< Functor, Fun>(fun)) {} //apply functions R apply() { return (*impl).apply(); } R apply(Param1 p1) { return (*impl).apply(p1); } private: std::auto_ptr<Impl> impl; }; --- 

When I try to use it like this:

 --- class TestFunctor0 { public: int operator()() { cout << "zero param functor" << endl; return 1; } }; //somewhere in main... TestFunctor0 f; Functor<int, NullType> command(f); int res = command.apply(); CPPUNIT_ASSERT_EQUAL(1, res); --- 

I get the following compile time error:

 ../../../include/real/Functors.hpp: In member function 'typename ParentFunctor::Impl::ResultType FunctionHandler<ParentFunctor, Fun>::apply(typename ParentFunctor::Impl::Param1) [with ParentFunctor = Functor<int, NullType>, Fun = TestFunctor0]': main.cpp:246: instantiated from here ../../../include/real/Functors.hpp:74: error: no match for call to '(TestFunctor0) (EmptyType&)' main.cpp:31: note: candidates are: int TestFunctor0::operator()() 

Does anyone understand why I am seeing this problem? I have no ideas. Thanks

+4
source share
1 answer

This issue has been resolved. It turns out that in FunctionHandler the presence of the apply () functions was virtually causing problems. As soon as I deleted the virtual keywords, everything went smoothly.

I'm still not quite sure why this changed the situation so much, but solved the problem. My best guess is that by adding a virtual machine, the compiler will try to populate the vtable with the correct functions, and since Param1 is / technically / defined by NullType, will it find that one?

Please correct me if I am wrong, this is just my best deal with limited understanding.

+1
source

All Articles