Marking function as virtual cause of compiler error with unique_ptr

I have a template class that wraps a vector. I am trying to save unique_ptrs in this class and it works fine. However, when I mark the void add(const T& elem) function as virtual, my compiler (clang) tells me that I am doing a “call to an implicitly deleted copy of the constructor” for unique_ptr.

I understand that unique_ptrs cannot be copied, so I created a void add(T&& elem) function void add(T&& elem) . I just don't know why marking another add function as a virtual cause of a compiler error.

Thank you for your time.

 #include <iostream> #include <vector> #include <memory> using namespace std; template <typename T> class ContainerWrapper { private: vector<T> vec; public: ContainerWrapper() : vec() { } //Marking this as virtual causes a compiler error void add(const T& elem) { vec.push_back(elem); } void add(T&& elem) { vec.push_back(std::move(elem)); } T removeLast() { T last = std::move(vec.back()); vec.pop_back(); return last; } }; int main() { ContainerWrapper<unique_ptr<string>> w; w.add(unique_ptr<string>(new string("hello"))); unique_ptr<string> s = w.removeLast(); cout << *s << endl; } 
+7
source share
2 answers

The problem is that std::unique_ptr has its own copy constructor marked as =delete . This means that calling vec.push_back(elem) inside add(T const&) overloaded member function will not compile when called with std::unique_ptr . The compiler will understand this as soon as this member function is created.

The standard contains 2 relevant quotes here in 14.7.1 Implicit Instance [temp.inst] :

6 If the overload resolution process can determine the correct function to call without an instance of the definition of the class template, it is unclear whether this is a creation.

10 [...] It is not clear whether the implementation implicitly creates an instance of the virtual member function of the class template, unless the virtual member function is otherwise created. [...]

Section 6 states that without the virtual compiler is allowed but not required to instantiate both add(T const&) and add(T&&) to decide which overload is best. Neither gcc 4.7.2 nor Clang 3.2 require instantiation because they infer that rvalue links are always better for temporary than lvalue links.

Section 10 states that - even with the virtual - the compiler is also allowed, but not required to instantiate add(T const&) and add(T&&) to decide which overload is best. Both gcc 4.7.2 and Clang 3.2 occur with instances of both member functions, although both of them could infer that lvalue overloading would never be a better match.

Please note: if you make ContainerWrapper regular class with a nested typedef unique_ptr<string> T; then gcc and Clang will generate errors with or without the virtual keyword, because they must generate code for both member functions. This will not be excluded from SFINAE because an error does not occur when substituting the output arguments.

Conclusion : this is not a mistake , but a problem .

+5
source

This is most likely due to the fact that ContainerWrapper is a template. With templates, the compiler most often does not even check member functions until you name them. However, mark it virtual, make the function present (you can also get a communication error).

You can take a look at this post: When are virtual member functions of a template class instantiated? .

+9
source

All Articles