Привет,
При создании универсальной обертки на основе 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()
в качестве аргумента по умолчанию для второго параметра в компиляторах TBase::Call(...)
:
static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TDerived_::Foo, TDerived_ pDerived = TDerived_() )
дает синтаксическую ошибку ... У меня такое ощущение, что это связано скак компилятор анализирует код и что он не может определить указатель на функцию еще не определенного (или созданного) класса.Однако у него нет проблем с вызовом конструктора TDerived
в качестве аргумента по умолчанию для третьего параметра TBase::Call(...)
.Может ли кто-нибудь дать мне определенный ответ о том, что происходит?Почему MFP производного класса не принимается, а объект производного класса принимается в качестве аргументов по умолчанию?
Спасибо.
EDIT: ошибка компилятора (компилятор командной строки 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_;
, как было указано (спасибо, ребята!).На самом деле, он компилируется только под 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 ++ принимает ее «по ошибке» (я думаю, вряд ли)? .. Помогите?!