The following does not compile with g++ 4.4.7, with --std==c++0x passed on the command line:
#include <algorithm>
#include <iostream>
template <typename T>
class A
{
public:
T v;
A() { std::cout << "A default constructor\n"; }
A(const A& i): v(i.v) { std::cout << "A copy constructor\n"; }
A(A&& i): v(std::move(i.v)) { std::cout << "A move constructor\n"; }
#if 1 // turn this off to fix the version without static_cast
template <typename V>
explicit A(const V& i): v(i) {}
#endif
};
class B: public A<int>
{
public:
B() { std::cout << "B default constructor\n"; }
#if 1 // turn this off to get static_cast that makes it compile
B(const B& i): A<int>(i) {
std::cout << "B copy constructor\n"; }
B(B&& i): A<int>(std::move(i)) {
std::cout << "B move constructor\n"; }
#else
B(const B& i): A<int>(static_cast<const A<int> &>(i)) {
std::cout << "B copy constructor\n"; }
B(B&& i): A<int>(std::move(static_cast<A<int> &&>(i))) {
std::cout << "B move constructor\n"; }
#endif
};
B foo() {
B t;
return t;
}
int main() {
B t(foo());
B t2(std::move(t));
std::cout << "Result is " << t2.v << std::endl;
return 0;
}
Produces the following error, where it seems the copy and move constructors call the explicit A template rather than the obvious copy/move constructors of A:
container.cpp: In constructor ‘A<T>::A(const V&) [with V = B, T = int]’:
container.cpp:26: instantiated from here
container.cpp:17: error: cannot convert ‘const B’ to ‘int’ in initialization
Turning off the first #if 1 removes the template and this compiles and produces the expected calls. Turning off the second #if 1 also makes it work (however doing the equivalent in our code would be painful and require vast amounts of careful editing).
Currently I work around this by changing the template constructor to this and adding the bool to all users, but that is ugly:
A(const V&i, bool dummy): v(i) {}
Questions:
- Is this a bug in GCC?
- If not, can somebody explain why this is happening?
- What is the suggested fix? Are my static_casts correct?