【发布时间】:2018-03-11 02:08:28
【问题描述】:
我遇到了一个小问题,我现在不明白,也找不到解释。我读到了如何在 PIMPL 成语中使用 std::unique_ptr 并且它可以工作,但是......不是在一种奇怪的情况下,这当然发生在我现在。
最简单的 - 我将展示一个重现问题的简化代码示例(使用 VS2017 社区编译)。
header.h ##
Forward类的Forward声明,模板类TestForward有返回unique_ptr的虚函数。
class Forward;
using TestUniquePtr = std::unique_ptr<Forward>;
TestUniquePtr make_ptr();
template<int a>
class TestForward {
public:
virtual TestUniquePtr foo();
};
template<int a>
TestUniquePtr TestForward<a>::foo() {
return make_ptr();
}
forward.h
#include "header.h"
#include <iostream>
class Forward {
public:
~Forward() {
std::cout << "HAAA" << std::endl;
}
};
forward.cpp
#include "forward.h"
TestUniquePtr make_ptr() {
return TestUniquePtr{ new Forward };
}
main.cpp
由于“无法删除不完整的类型”而无法编译的文件。
请注意,这里甚至没有调用函数 foo。
那么编译器应该尝试在这个单元中编译这个函数吗?
如果此函数不是虚拟函数或 TestForward 不是模板 - 它可以工作。
#include "header.h"
int main (int argc, char *argv[]) {
TestForward<3> a;
return 0;
}
我知道如何解决这个问题 - 通过定义不是模板的删除器,并将其定义写在 forward.cpp 但是.. 我认为这应该可行,所以请帮助我找出为什么模板+虚拟使它成为不工作:(
【问题讨论】:
-
foo无论如何都会被实例化以填充 vtable。并且类型Forward必须在foo定义处完整,因为它涉及到make_ptr返回的临时对象的移动和销毁。