5

「ModernC++Design」という本の第5章(一般化されたファンクター)に基づいています。

ファンクターテンプレートを作成しようとしています。「ブーストのバインドやロキを真っ直ぐに使ってみませんか?」と尋ねる前に。簡単な答えは「学びたいから」です。

そうは言っても、私はこの本を読み、サンプルコードも参照として使用しましたが、コンパイル時のエラーが発生し続けており、その理由が理解できないようです。

スレッドモデルを使用しないように本のサンプルコードを変更すると、サンプルは正常に機能します。しかし、私のコードはそうではありません。関連するコードは次のとおりです。

非常に基本的なTypeListと、TypeAtおよびNulltype、EmptyType(これも本に基づいています)

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

もちろん、これらを使用するのはファンクターです

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

};

---

私がこのようにこれを使おうとすると:

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

次のコンパイル時エラーが発生します。

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

私がこの問題を抱えている理由を誰かが理解していますか?私は考えが足りません。ありがとう

4

1 に答える 1

1

この問題は解決されました。FunctionHandlerで、apply()関数を仮想化すると、問題が発生することがわかりました。仮想キーワードを削除すると、すべてがスムーズに進みました。

なぜこれが劇的に物事を変えたのかはまだよくわかりませんが、問題は解決しました。理由の私の最もよい推測は、仮想を追加することによって、コンパイラはvtableに正しい関数を入力しようとし、Param1は/技術的に/ NullTypeによって定義されているので、それを見つけるだろうか?

私が間違っている場合は訂正してください。これは、理解が限られている私の最善の策です。

于 2010-08-05T08:04:29.787 に答える