やあ、
CRTPベースの汎用ラッパーを作成して任意のライブラリ関数を呼び出すときに、理解しにくい問題が発生しました。問題を説明するための非常に単純化されたコードを次に示します。
#include <iostream>
template< typename PValue, typename PDerived >
class TBase
{
private:
typedef TBase TSelf_;
typedef PDerived TDerived_;
protected:
typedef PValue TValue_;
protected:
TBase( void )
{
std::cout << " TBase::TBase() " << std::endl;
}
public:
void Foo( void )
{
std::cout << " TBase::Foo() " << std::endl;
}
template< typename PType >
static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TSelf_::Foo, TDerived_ pDerived = TDerived_() )
{
( pDerived.*pFunction )();
std::cout << " static TBase::Call(). " << std::endl;
}
};
template< typename PValue >
class TDerived : public TBase< PValue, TDerived< PValue > >
{
friend class TBase< PValue, TDerived< PValue > > ;
private:
typedef TBase< PValue, TDerived > TBase_;
typedef TDerived TSelf_;
public:
TDerived( void ) :
TBase_()
{
std::cout << " TDerived::TDerived() " << std::endl;
}
void Foo( void )
{
std::cout << " TDerived::Foo() " << std::endl;
}
void Bar( void )
{
std::cout << " TDerived::Bar() " << std::endl;
}
};
int main( void )
{
TDerived< int >::Call( 1 );
TDerived< int >::Call( 1, &TDerived< int >::Foo );
TDerived< int >::Call( 1, &TDerived< int >::Bar, TDerived< int > () );
return ( 0 );
}
すべてが意図したとおりにコンパイルおよび動作します。ただし、 :TDerived::Foo()
の2番目のパラメーターのデフォルト引数としてポインターを使用しようとすると、TBase::Call(...)
static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TDerived_::Foo, TDerived_ pDerived = TDerived_() )
コンパイラーは構文エラーを出します...コンパイラーがコードを解析する方法に関連していて、まだ定義されていない(またはインスタンス化されていない)クラスの関数へのポインターを理解できないと感じています。ただし、TDerived
の3番目のパラメーターのデフォルト引数としてコンストラクターを呼び出すことは問題ありませんTBase::Call(...)
。誰かが私に何が起こっているのかについて明確な答えを与えることができますか?派生クラスMFPが受け入れられず、派生クラスのオブジェクトがデフォルトの引数として受け入れられるのはなぜですか?
ありがとう。
編集:コンパイラのエラー(MSVS2010コマンドラインコンパイラ):
FMain.cpp(224) : error C2061: syntax error : identifier 'TDerived_'; FMain.cpp(233) : see reference to class template instantiation 'TBase<PValue,PDerived> with [PValue=int,PDerived=TDerived<int>]' being compiled; FMain.cpp(323) : see reference to class template instantiation 'TDerived<PValue> with [PValue=int]' being compiled
TDerived_
これは構文エラーです。MFPのデフォルト引数のタイプとして認識されません。これに続いて他のエラーがあります。関数定義の形式が正しくないため、これらはすべて構文エラーです。それが私がそれを理解する方法です。
編集:基本的に、オブジェクトをデフォルトの引数として使用できる理由はわかりませんがTDerived_
、メンバー関数へのポインターをデフォルトの引数として使用することはできません。
編集:わかりました、これは今私を夢中にさせています。まず、typedef TBase< PValue, TDerived > TBase_;
指摘された通りに変更しました(ありがとうございます!)。実際、このコンパイラは2つの部分からなる解析を行わないため、MSVC++でのみコンパイルされます。つまり、codepad.org(g ++ 4.1.2を使用)ではコンパイルされませんでした。static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TDerived_::Foo, TDerived_ pDerived = TDerived_() )
次に、 codepad.orgで使用してみましたが、コンパイルされて正しく実行されました。だから私は今本当に混乱しています:人々はそれが正しくない理由を私に説明しました(そして私は「なぜ」を理解できませんでした(私の前の編集を参照してください))そして今それはg++がそれを正しくコンパイルすることがわかります...それはちょうどそれを意味しますかコードではなくMSVC++の問題?または、コードには標準の観点から問題があり(そして私はそれを見ることができません)、g ++はそれを「誤って」受け入れます(おそらく、私は思いません)?..ヘルプ?!