2010-08-05 6 views
4

Basé sur le chapitre 5 (Generalized Foncteurs) du livre "Modern C++ Design"C++ basé sur des modèles Functor (basé sur la conception moderne C++) erreur de compilation

Je suis en train d'écrire un modèle Functor. Avant de me demander "pourquoi je n'utilise pas la reliure de Boost ou Loki?" la réponse simple est "parce que je veux apprendre." Cela étant dit, j'ai suivi le livre, et aussi utilisé le code de l'exemple comme référence, mais je continue à commettre des erreurs de compilation et je n'arrive pas à comprendre pourquoi.

Lorsque je modifie le code d'exemple du livre pour ne pas utiliser les modèles de thread, les exemples fonctionnent correctement. Mais mon code ne le fait pas. Voici le code relevent:

TypeList très basique, avec le TypeAt et type_null, EmptyType (également basé sur le livre)

<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; 
}; 
} 
--- 

à l'aide de ceux-ci est bien sûr la 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; 

}; 

--- 

Lorsque je tente d'utiliser comme ceci:

--- 
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); 
--- 

Je reçois f erreur de compilation suivante:

../../../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()() 

Est-ce que quelqu'un comprend pourquoi je vois ce problème? Je n'ai plus d'idées. Merci

+0

Comment les fonctions const s'appliquent dans Functor appellent les versions non const dans FunctionHandler? Est-ce qu'il me manque quelque chose? – ngoozeff

+0

l'état des valeurs membres dans FunctionHandler ne sont pas modifiés même si l'objet Fun sous-jacent est. Au moins, c'est ma compréhension (ce qui pourrait être faux). En outre, je les ai supprimés et j'ai toujours la même erreur. Je vais modifier le code affiché pour ajuster pour cela – Nik

+0

Lors d'une lecture occasionnelle, il n'est pas clair pour moi ce que vous essayez de faire. Pourquoi avez-vous besoin des différentes macros et modèles de typistes? En général, je ne permettrais pas que le code soit alambiqué à moins qu'il y ait eu des commentaires détaillés expliquant comment cela fonctionnait et pourquoi cela était nécessaire. (Just FYI) –

Répondre

1

Ce problème a été résolu. Il s'avère que dans FunctionHandler, avoir les fonctions apply() être virtuel était à l'origine des problèmes. Une fois que j'ai supprimé les mots-clés virtuels, tout s'est bien passé.

Je ne sais toujours pas pourquoi cela a changé les choses de manière aussi drastique, mais cela a résolu le problème. Ma meilleure estimation de la raison est qu'en ajoutant virtual, le compilateur va essayer de peupler le vtable avec les fonctions correctes, et puisque Param1 est/technically/étant défini par NullType, il trouvera celui-là?

S'il vous plaît corrigez-moi si je me trompe, c'est tout simplement mon meilleur résultat avec une compréhension limitée.

+1

Votre estimation est correcte.Avec les fonctions étant 'virtual', le compilateur essaiera d'instancier toutes les fonctions, car il a besoin des adresses pour le vtable. Avec des fonctions non -virtual', le compilateur essaie seulement d'instancier les fonctions réellement appelées. –

Questions connexes