Subclass insists on calling a template rather than constructor
c++, c++11, copy-constructor, templates
Solution
where it seems the copy and move constructors call the explicit A template rather than the obvious copy/move constructors of A:
There’s nothing obvious about calling the `A(A const&)` constructor: you’re calling the `A` constructor with an argument of type `B const&`, and the best match for this is simply the template (which is an exact match) rather than `A(A const&)`, which is not an exact match (it requires an implicit upcast).
So this behaviour is exactly as expected. If you don’t want this, change the template so that it’s disabled when called with a subclass of `A` (via SFINAE):
template <typename V>
explicit A(const V& i,
typename std::enable_if<! std::is_base_of<A, V>::value>::type* = nullptr)
: v(i) {}
(untested!)
Problem
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?