你好呀,
在制作基于 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 不被接受,而派生类的对象被接受为默认参数?
谢谢。
编辑:编译器的错误(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 ++“错误地”接受它(我认为不太可能)?..帮助?!