我知道unique_ptrs无法复制,因此我创建了void add(T&& elem)函数.我只是不知道为什么将其他添加函数标记为虚拟导致编译器错误.
谢谢你的时间.
- #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;
- }
解决方法
Standard在14.7.1隐式实例化[temp.inst]中有2个相关引用:
6 If the overload resolution process can determine the correct
function to call without instantiating a class template definition,it
is unspecified whether that instantiation actually takes place.10 […] It is unspecified whether or not an implementation implicitly
instantiates a virtual member function of a class template if the
virtual member function would not otherwise be instantiated. […]
第6条规定 – 没有虚拟关键字 – 允许编译器但不要求实例化add(T const&)和add(T&&)以便解决哪个过载是最佳匹配. gcc 4.7.2和Clang 3.2都不需要实例化,因为它们恰好推断出rvalue引用总是比临时引用更适合临时.
第10条规定 – 即使使用virtual关键字 – 也允许编译器但不需要实例化add(T const&)和add(T&&)以便解决哪个重载是最佳匹配. gcc 4.7.2和Clang 3.2都碰巧实例化了两个成员函数,即使它们都可以推断出左值超载永远不会是更好的匹配.
请注意,如果您使ContainerWrapper成为具有嵌套typedef的常规类unique_ptr< string> T;,然后gcc和Clang都会生成带或不带virtual关键字的错误,因为它们必须为两个成员函数生成代码.这不会是SFINAE,因为在替换推断的参数期间不会发生错误.
结论:这不是一个错误,而是一个实施质量问题.