【发布时间】:2011-11-19 04:28:43
【问题描述】:
你好,
在制作基于 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_() )
compilers 给出了一个语法错误...我感觉它与编译器如何解析代码有关,并且它无法找出指向尚未定义(或实例化)类的函数的指针。但是,调用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)上它没有编译。
其次,在那之后,我尝试在 codepad.org 上使用static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TDerived_::Foo, TDerived_ pDerived = TDerived_() ) 并且......它编译并正确运行!所以我现在真的很困惑:人们向我解释了为什么它不正确(而且我无法理解“为什么”(参见我以前的编辑)),现在事实证明 g++ 可以正确编译它......这是否意味着它只是MSVC++ 问题而不是代码?或者从标准的角度来看,代码确实有问题(我看不到)并且 g++ “错误地”接受了它(我认为不太可能)?.. 帮助?!
【问题讨论】:
-
编译器给出了什么错误?你为什么不也发布呢?是不是你要我们编译这段代码,自己看看错误?
-
“语法错误”错误消息可能是最没用的诊断消息(“某处有错误”除外)。
-
回复:您最近的 cmets - 在 typedef 更改后对我来说代码看起来不错,但也许对标准有更广泛了解的人可以发表评论。 FWIW,更改后它会在 VS2008 和 GCC 4.2.1 上为我编译和运行。
标签: c++ templates crtp pointer-to-member