模板生成器错误的显式复制构造函数
explicit copy constructor for template generator error
将旧代码从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 );
(虽然保持显式);对同ant的呼吁是完全专业的:
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 标准中的一些东西,这些标准阻止了在新编译器下编译的旧代码。我试图在这里找到一个解决方案,但是我不能,对不起,如果这是重复的。请帮助我解决它或至少了解问题的根源。
将其传递给allocT
函数时,您执行BBB
的意外副本。这会导致编译器错误。
您在这里调用分配函数:
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 ) { ... }
或将其传递给allocT
时,您会明确复制BBB
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 );
}
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用