模板生成器错误的显式复制构造函数

问题描述 投票:2回答:1

将旧代码从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,因为它看起来很可疑 - 看起来编译器试图创建一个临时的并将其传递得更远;
  • 删除默认参数有效地防止构造函数成为复制构造函数,并可能生成编译器定义的版本,稍后用于创建临时版本;
  • 每次都指定所有构造函数参数类型并不方便。我只想将参数转发给BBB的构造函数。

试图理解为什么编译器不能将*this分配到const BBB &,我创建了一个测试助手函数,它将指针显式转换为const引用,这也没有帮助:

template const T & deref( const T * ptr ) { ... } ... return dst.allocT( deref(this), param );

关于源代码的几点说明:

  • TTT是一种智能指针,它不能被标准智能指针取代,因为它提供了非标准功能;
  • AAA和BBB实际上是非常重的类,它们被引用计数,因此复制它们是非常不理想的。

在代码移植中这是一个非常难以置信的问题,我在这里完全不解。似乎我错过了现代C ++标准中的一些东西,它可以防止在新编译器下编译旧代码。我试图在这里找到一个解决方案,但我不能,抱歉,如果它是重复的。请帮助我解决它或至少了解问题的根源。

c++ porting explicit
1个回答
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

或者你将allocT传递给inline bool BBB::dup( TTT<AAA> & dst, bool param ) const { return dst.allocT<BBB>( BBB(*this), param ); } 时明确地复制你的inline bool BBB::dup( TTT<AAA> & dst, bool param ) const { return dst.allocT<BBB>( static_cast<BBB>(*this), param ); }

qazxswpoi

或者(从C ++ 17开始)

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.