依赖于模板扩展的方法中的错误仅在显式调用方法时出现编译器错误。虽然当该方法被标记为虚拟时,但无论是否实际调用它,都会产生编译器错误。 C ++标准中有没有解释为什么将这些方法标记为虚拟导致编译器错误的原因?
#include <memory>
#include <iostream>
template <class T_>
class Foo
{
protected:
T_ data;
public:
Foo(const T_& x) : data(x) { }
Foo(T_&& x) : data(std::move(x)) { }
// comment these two lines out and it works fine.
virtual void test(T_& x) = 0;
virtual void test(T_&& x) = 0;
};
template <class T_>
class Bar : public Foo<T_>
{
public:
using Foo<T_>::Foo;
void test(T_& x)
{
std::cout << "test(&)" << std::endl;
x = this->data;
}
void test(T_&& x)
{
std::cout << "test(&&)" << std::endl;
x = std::move(this->data);
}
};
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
}
答案 0 :(得分:2)
virtual
函数的覆盖率总是使用 - 也就是说,它们的定义必须存在,无论它们是否在翻译单元中明确使用。
virtual
的覆盖者函数本身是virtual
([class.virtual] / 2),必须定义所有virtual
函数([basic.def.odr] / 3和4)。
现在的问题是派生类中的test
重载是否实际实例化了。
对于模板,标准要求
除非是类模板的成员[...] 显式实例化或明确专门化,专业化 当特化是隐式实例化成员的时候 在需要成员定义存在的上下文中引用;
对于虚拟功能,人们可能会争辩说他们的存在足以需要定义。但是,标准并没有将自己束缚下来,而是决定实施,[temp.inst] / 11:
是否隐式指定了实现 如果是,则实例化类模板的虚拟成员函数 否则将不会实例化虚拟成员函数。
答案 1 :(得分:0)
将其设为虚拟是强制实例化。在注释掉基类中的虚函数后,我得到了与以下测试代码相同的错误:
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
x.test(std::unique_ptr<int>(new int(99)));
std::unique_ptr<int> pi;
x.test(pi);
std::cout << "test returned " << *pi << std::endl;
}
无法实例化带参考的版本,因为std::unique_ptr
不可分配。