4

我想在使用它们之后从我的包含链中排除一些标题。据我所知,c ++ 11中没有排除“header.h”。

伪代码一厢情愿:

#include "the_bad_header.h" //long includechain with later unused declarations
class bulky { ... };
constexpr std::size_t bulkysize = sizeof(bulky);
forget everything included and class bulky and remember only bulkysize

我的问题变得明显的例子如下。请不要争辩这不是一个严重的问题。该示例被分解以显示最小的抽象语言使用。我还将描述老式的解决方案及其缺点。

旧式解决方案

只是另一个header.h:

class bulkywrap
{
public:
    bulkywrap();
protected:
    friend class bulkywrap_pImpl;
    bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
};

只是另一个cppunit.cpp:

#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on

class bulkywrap_pImpl
{
    //lots of members of types used from the other libraries
};

bulkywrap::bulkywrap()
: pImpl( new bulkywrap_pImpl() )
{}

我目前的解决方案

只是另一个header.h:

#include "stdint.h" // this is the only header I like to use, but also unnecessary.
#define UNKNOWNSIZE 12345
class bulkywrap
{
public:
    bulkywrap();
protected:
    friend class bulkywrap_pImpl;
    bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
    uint8_t pImpl_Placement[UNKNOWNSIZE]; //placement new for pImpl
};

只是另一个cppunit.cpp:

#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on

class bulkywrap_pImpl
{
    //lots of members of types used from the other libraries
};

bulkywrap::bulkywrap()
: pImpl( new(this->pImpl_Placement) bulkywrap_pImpl() ) //using this here is safe
{}

因此,上面的代码正在运行。优点是:隐藏复杂性并且没有运行时动态内存间接。嗯?我的意思是,放置 new 允许将整个对象放在堆栈上,并且所有成员地址在编译时都是已知的。我的尝试是在使用不透明指针的界面设计时获得最佳性能。

如果您认为:“这种性能优势不值得思考。” 那么请留下这个问题。


我预期的解决方案

只是另一个header.h:

#include "stdint.h" // this is the only header I like to use, but also unnecessary.

constexpr std::size_t get_bulkywrap_pImpl_Size( void ); //constexpr function forward declaration
extern constexpr std::size_t bulkywrap_pImpl_Size; //constexpr literal forward declaration with external initialization

class bulkywrap
{
public:
    bulkywrap();
protected:
    friend class bulkywrap_pImpl;
    bulkywrap_pImpl *const pImpl; //opaque pointer, private implementation
    uint8_t pImpl_Placement[get_bulkywrap_pImpl_Size()]; //undefined constexpr used
    uint8_t pImpl_Placement[bulkywrap_pImpl_Size]; //alternative to above. undefined constexpr used
};

只是另一个cppunit.cpp:

#include "justanotherheader.h"
#include "boost/lotsofheaders.hpp"
//#include more and more headers of highly complex libraries so adding millions of known types and other identifiers, macros, and so on

class bulkywrap_pImpl
{
    //lots of members of types used from the other libraries
};

constexpr std::size_t get_bulkywrap_pImpl_Size( void )
{
    return sizeof(bulkywrap_pImpl);
}
constexpr std::size_t bulkywrap_pImpl_Size = sizeof(bulkywrap_pImpl);

bulkywrap::bulkywrap()
: pImpl( new(this->pImpl_Placement) bulkywrap_pImpl() ) //using this here is safe
{}

在我当前的解决方案中,我需要验证 sizeof(bulkywrap_pImpl) 并手动调整 UNKNOWNSIZE。我认为目前无法从编译单元获取任何信息给其他人。我知道这通常是有充分理由的,但这限制了 c++11 的可能性。

我想指出:

jtc1 sc22 wg21 纸 n3337

jtc1 sc22 wg21 纸 n3308

请帮我查找信息天气以及为什么标准不允许这样做。

但此外,我想找到一种解决方案,如何在编译期间将一些文字常量从一个编译单元导出到另一个编译单元。它只是一个文字,所以所有的语句和表达式都不受它的影响。因此编译不依赖于数组的大小来自哪里。

我的建议为 ISO-jtc1-sc22-wg21 和编译器开发人员带来了一些工作,但我没有看到模板和 constexpr 之间有任何相关差异,因为每个定义都必须出现在同一个翻译单元中。这使得模块化编程和干净的接口变得虚假。

不:我不想使用预处理器宏、动态新函数或虚拟成员函数。重要的是最大的 const 正确性,因为类的大小是 const。

请帮忙

4

2 回答 2

2

您不能同时拥有“编译时”和“来自另一个编译单元”。也不清楚为什么你需要忘记成功解析的标题。解析时间已经消耗。我建议您创建另一个大小为常量的标头,从两个文件中包含它,并将 static_assert 添加到 pimpl 文件中,检查constant >= sizeof(pimpl). 您可以通过编译源文件(包括 pimpl 和doing cout <<sizeof(pimpl). 我还建议您不要为 pimpl 指针浪费时间和空间,并将其替换为成员函数,返回正确转换缓冲区的地址。你也没有显示你在哪里调用 pimpl 的析构函数。实现分配/复制/移动/交换也会很有趣

于 2013-02-20T13:24:29.530 回答
0

在 cpp 中使用 static_assert 检查标头中声明的大小 >= impl 类的大小

于 2018-07-11T15:24:45.737 回答