C++ 中存在的问题是部分实现,即内联函数和私有(private)成员变量,会泄漏到头文件中。使用 LTO 时不再需要内联函数(constexpr 函数除外)。 header 中有私有(private)变量的解决方法,例如Pimpl 成语,但它们有其缺点,即使用起来很麻烦和/或性能不理想。在我看来,这个问题目前存在一个简单的解决方案:允许前向声明类/结构并手动指定它们的大小。我们已经在 C++ 中有这个概念用于枚举。可以使用枚举,例如在已知命名值之前作为结构的成员:
enum E : int;
struct S
{
E e;
float foo;
};
如果我们现在将此概念扩展到类/结构的前向声明,我们可以执行以下操作(我现在借用位字段的语法来指定大小):// header s.h
// forward declare SVariables and tell the compiler it is 16 bytes in size
struct SVariables : 16;
class S : private SVariables
{
public:
void foo();
};
// implementation s.cpp
struct SVariables
{
float x, y, z, w;
};
void S::foo()
{
x = 1.0f;
}
程序员有责任在前向声明中指定正确的或足够大的大小(枚举也是如此)。但是,当类/结构完全定义并且之前指定的大小不匹配或太小时,错误会立即导致实现文件中的编译器错误。(如果前向声明的类/结构不是微不足道的,编译器可能无法自动生成特殊的成员函数,例如构造函数、析构函数、复制构造函数等。)
标题问题的答案当然是:因为标准不允许。所以我想问以下问题:
(我在 www 上真的找不到类似上述概念的东西,所以如果这已经在某个地方讨论过,请见谅。)
谢谢,
知乎
最佳答案
这可能是因为这在图书馆中相当容易实现,但这种设施并未广泛使用,表明需求不足。例如:
#include <cstddef>
#include <new>
#include <utility>
template<std::size_t Size, std::size_t Align, class T>
struct fwd {
alignas(Align) std::byte buf[Size];
template<class... Args> requires (sizeof(T) <= Size && alignof(T) <= Align &&
!std::is_same_v<fwd(std::remove_cvref_t<Args>...), fwd(fwd)>)
fwd(Args&&... args) { new (buf) T(std::forward<Args>(args)...); }
fwd(fwd&& rhs) : fwd(std::move(rhs.get())) {}
fwd(fwd const& rhs) : fwd(rhs.get()) {}
fwd& operator=(fwd&& rhs) { get() = std::move(rhs.get()); return *this; }
fwd& operator=(fwd const& rhs) { get() = rhs.get(); return *this; }
~fwd() { get().~T(); }
T& get() { return *std::launder(reinterpret_cast<T*>(buf)); }
T const& get() const { return *std::launder(reinterpret_cast<T const*>(buf)); }
};
Example .实际上,如果您要支付编译器障碍的优化损失,而 LTO 并不能完全消除,那么免费存储分配的额外成本将不会特别明显,并且具有永远不必这样做的显着优势更改大小或对齐方式(是的,即使您提前计划)。
关于c++ - 为什么我们不能在 C++ 中转发声明具有已知大小的类/结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66584173/