Reputation: 23
Being porting old code from MSVS2003 to MSVS2017 and ran into problems. The following code (an excerpt) is compiled fine under MSVS2003 and fails under 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 );
}
The exact error message is
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'
This error disappears if one of following is done:
explicit
(as the compiler advises);the `param' parameter of constructor is declared non-default:
explicit BBB( const BBB & src, bool param );
(remaining explicit though);
the call to allocT is fully specialized:
return dst.allocT< BBB, const BBB &, bool >( *this, param );
None of these solutions suits me:
explicit
since it looks suspicious -- it looks like the compiler is trying to create a temporary and pass it further;Trying to understand why the compiler cannot assign *this
into const BBB &
, I created a test helper function which explicitly converts a pointer into const reference and this didn't help either:
template const T & deref( const T * ptr ) { ... }
...
return dst.allocT( deref(this), param );
Several notes on the source code:
It's very unexpectable problem in code porting, I'm totally puzzled here. Seems that I missed something in modern C++ standard that prevents old code of being compiled under new compilers. I tried to find a solution here on SO but I couldn't, sorry if it's a duplicate. Please help me to solve it or at least understand the roots of the problem.
Upvotes: 2
Views: 182
Reputation: 9825
You perform an accidental copy of BBB
when you pass it to your allocT
function. That causes the compiler error.
You are calling the allocation function here:
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( *this, param );
}
Because your allocation function takes its arguments as values, they will be copied:
template<typename X, typename P1, typename P2>
bool allocT( P1 p1, P2 p2 ) { ... }
However this is an implicit (hidden) copy, because you don't explicitly specify to copy the object (this
in your case). Since you declared your copy constructor explicit
these copy invocations aren't allowed anymore.
To fix it you can either change allocT
to take a reference (which I recommend)
template<typename X, typename P1, typename P2> bool
allocT( P1 const& p1, P2 p2 ) { ... }
or you explicitly copy your BBB
when passing it to allocT
like
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( BBB(*this), param );
}
or (since C++17)
inline bool BBB::dup( TTT<AAA> & dst, bool param ) const
{
return dst.allocT<BBB>( static_cast<BBB>(*this), param );
}
Upvotes: 4