如果我创建一个这样的类:
// B.h
#ifndef _B_H_
#define _B_H_
class B
{
private:
int x;
int y;
};
#endif // _B_H_
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
// main.cpp
#include <iostream>
#include <vector>
class B; // Forward declaration.
class A
{
public:
A() {
std::cout << v.size() << std::endl;
}
private:
std::vector<B> v;
};
int main()
{
A a;
}
Run Code Online (Sandbox Code Playgroud)
编译时编译器失败main.cpp.现在我知道的解决方案是#include "B.h",但我很好奇为什么它失败了.无论是g++或cl的错误信息都在这个问题很有启发.
TIL以下程序是合法的以及诸如此类的:
#include <vector>
struct Bar;
struct Foo
{
using BarVec = std::vector<Bar>::size_type;
};
struct Bar {};
int main()
{
Foo f;
}
Run Code Online (Sandbox Code Playgroud)
怎么样?Bar是一个不完整的类型,因此编译器无法知道std::vector<Bar>它是什么,或者它包含一个成员size_type,或者该成员size_type是一个类型.
我能想出的唯一解释是,任何假设的专业化(可能)都必须已经在范围内导致size_type与"基础"模板定义中给出的含义不同,并且size_type不是从属名称(两者都是有助于编译器确定性的因素).
这里的法律理由是什么?
为什么 C++不允许实例化不完整类型的容器?
编写没有这个限制的容器当然是可能的 - boost :: container完全能够做到这一点.据我所知,它似乎没有给出任何性能或其他类型的增益,但标准声明它是未定义的行为.
例如,它确实阻止了构建递归数据结构.
为什么C++标准会强加这种任意限制呢?尽可能允许不完整类型作为模板参数的缺点是什么?
这段代码肯定是格式错误的,因为它Foo是在实例化点之后专门化的:
template <typename T>
struct Foo {
int a;
};
Foo<int> x = { 42 };
template <>
struct Foo<int> {
const char *a;
};
Foo<int> x = { "bar" };
Run Code Online (Sandbox Code Playgroud)
由于我强调的标准部分,它形成不良:
函数模板,成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元内具有多个实例化点,并且除了上述实例化的点之外,对于任何这样的实例化.在翻译单元内具有实例化点的专门化,翻译单元的末尾也被认为是实例化的点.类模板的专门化在翻译单元中最多只有一个实例化点.任何模板的特化可以在多个翻译单元中具有实例化点.如果两个不同的实例化点根据单定义规则给出模板特化的不同含义,则程序形成错误,不需要诊断.
现在,这个代码是不正确的吗?
struct A;
template <typename> class Foo { };
Foo<A> foo; // note A is incomplete here
struct A {};
Run Code Online (Sandbox Code Playgroud)
如果这样Foo宣布,那么不良形象会改变吗?
struct A;
template <typename T>
struct Foo {
Foo() {
new T;
}
};
Foo<A> foo; // …Run Code Online (Sandbox Code Playgroud) vector我有一个带有成员变量的类T,该变量已声明但未定义。如果没有定义该类的析构函数,这可能会出现问题,因为编译器可能会选择其他一些翻译单元来生成析构函数。如果该 TU 没有 的定义,则T编译会失败。
struct undefined;
struct S
{
S(int);
std::vector<undefined> v;
};
int main()
{
S s(42); // fails in ~vector(), `undefined` is undefined
}
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我通常在实现该类的文件中添加一个默认的析构函数作为锚点,该类可以访问该定义。
struct undefined;
struct S
{
S(int);
~S(); // implemented in another TU as `S::~S() = default;`
std::vector<undefined> v;
};
int main()
{
S s(42); // ok
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试对继承基类构造函数的派生类执行相同的操作:
#include <vector>
struct undefined;
struct base
{
base(int);
};
struct derived : base
{
using base::base;
~derived();
std::vector<undefined> v;
}; …Run Code Online (Sandbox Code Playgroud)