c++ - 为什么我们不能在 C++ 中转发声明具有已知大小的类/结构?

标签 c++

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/

    相关文章:

    c# - 适用于 Windows 8(开发人员预览版)的任何好的简单 DirectX 示例?

    c++ - 在 C++ 中,系统如何实现缓冲流?

    c++ - 减慢 Windows 进程?

    c++ - EndUpdateResource() throws Error 110 在输出位置打开windowsexplorer时系统无法打开指定的设备或文件

    c++ - Windows Mobile 中的触摸友好 GUI

    c++ - 哪些文件包含 malloc() 和 new() 的实现?

    c++ - 通过查看程序集比较按值传递与按引用传递的性能

    c++ - 快速排序不排序高范围的数字

    c++ - 打开多个文件,替代 fopen()

    c++ - 使用 set-width 对齐列