正在将旧代码从MSVS2003移植到MSVS2017并遇到问题。下面的代码(摘录)在MSVS2003下可以很好地编译,而在MSVS2017下失败:
template<typename T> class TTT
{
public:
template<typename X, typename P1, typename P2> bool allocT( P1 p1, P2 p2 )
{
p = new X( p1, p2 );
return true;
}
T * p;
};
struct AAA
{
virtual ~AAA(){}
virtual bool dup( TTT<AAA> & dst, bool param ) const = 0; // require dup method in all derived classes
};
struct BBB : public AAA
{
explicit BBB( const BBB & src, bool param = false );
bool dup( TTT<AAA> & dst, bool param ) const override;
};
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( *this, param );
}
确切的错误消息是
1>[...]: error C2664: 'bool TTT<AAA>::allocT<BBB,BBB,bool>(P1,P2)': cannot convert argument 1 from 'const BBB' to 'BBB'
1> with
1> [
1> P1=BBB,
1> P2=bool
1> ]
1> [...]: note: Constructor for struct 'BBB' is declared 'explicit'
完成以下任一操作,此错误就会消失:
explicit
(如编译器所建议); 构造函数的“ param”参数被声明为非默认值:
explicit BBB( const BBB & src, bool param );
(尽管仍然是明确的);
对allocT的调用是完全专门的:
return dst.allocT< BBB, const BBB &, bool >( *this, param );
这些解决方案都不适合我:
explicit
,因为它看起来很可疑-看起来编译器正在尝试创建一个临时文件并将其进一步传递; 试图理解为什么编译器无法将*this
分配给const BBB &
,我创建了一个测试帮助器函数,该函数将指针明确转换为const引用,但对这也没有帮助:
template const T & deref( const T * ptr ) { ... }
...
return dst.allocT( deref(this), param );
关于源代码的几点注释:
在代码移植中这是非常无法预料的问题,我在这里完全感到困惑。似乎我错过了现代C ++标准中的某些内容,这些内容阻止了旧代码在新编译器下进行编译。我试图在此处找到一种解决方案,但我不能,抱歉,如果重复的话。请帮助我解决该问题,或者至少了解问题的根源。
答案 0 :(得分:3)
将BBB
传递给allocT
函数时,会执行意外复制。这会导致编译器错误。
您在这里调用分配函数:
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( *this, param );
}
由于您的分配函数将其参数作为值,因此将被复制:
template<typename X, typename P1, typename P2>
bool allocT( P1 p1, P2 p2 ) { ... }
但是,这是一个隐式(隐藏)副本,因为您没有明确指定要复制对象(在您的情况下为this
)。自从您声明了副本构造函数explicit
以来,这些副本调用不再被允许。
要解决此问题,您可以更改allocT
以获取参考(我建议)
template<typename X, typename P1, typename P2> bool
allocT( P1 const& p1, P2 p2 ) { ... }
或者您将BBB
像{p>一样传递给allocT
时显式复制
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( BBB(*this), param );
}
或(自C ++ 17起)
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( static_cast<BBB>(*this), param );
}