从构造函数二进制文件中删除“显式”是不是兼容?

Posted

技术标签:

【中文标题】从构造函数二进制文件中删除“显式”是不是兼容?【英文标题】:Is removing 'explicit' from a constructor binary compatible?从构造函数二进制文件中删除“显式”是否兼容? 【发布时间】:2017-01-21 23:06:44 【问题描述】:

我们正在使用的外部库包含以下显式构造函数:

class Chart 
public:
    explicit Chart(Chart::Type type, Object *parent);
    // ...
;

编译器抱怨以下警告:

chart.h: warning #2305: declaration of 'explicit' constructor
without a single argument is redundant

只删除chart.h 中的explicit 关键字而不重新编译库以避免警告是否是二进制兼容的?我的感觉是它是安全的,因为explicit 在这种情况下无论如何都没有意义。谁能确认一下?

【问题讨论】:

关闭愚蠢的警告。 我想这是最好的建议 :-) 警告在 C++11 之前非常有意义。如果你的编译器是 c++11 之前的,你可能会遇到 c++11 代码更严重的问题,所以你可能应该考虑升级。 【参考方案1】:

如果你明白我的意思,你最好的选择是在包含期间关闭该警告。 不要破解供应商代码。

explicit 用于多参数构造函数在 C++11 及以后的版本中非常有意义,因为它可用于停止隐式大括号初始化。此外,标准并没有说删除explicit 必须保留类的布局,因此您必须假设删除explicit 可以 打破二进制兼容性。此外,删除它可能会改变人为的 SFINAE 模式的行为,因为该构造函数在某些情况下可能会重新可用。见http://en.cppreference.com/w/cpp/language/sfinae。

【讨论】:

【参考方案2】:

explicit 在 C++11 及更高版本的大括号初始化器上下文中对多个参数有意义:

void foo(Chart const &);

// ...

// Will only compile without `explicit`
foo(Chart::Type::pie, myObj);

删除explicit 是否二进制兼容最终取决于您的编译器,因此您必须在其文档中找到它。

但是,由于 explicit 是一种高级语言功能,它只用于重载解析,我不希望它破坏兼容性只要它不改变某些 pre 的最佳匹配- 现有调用,包括您从库本身编译的任何代码(模板和/或内联函数)

也就是说,这是纯粹的临时补丁:根据标准,这样做会让你直接进入 UB 领域。引用n.m.的评论:

摆弄这样的标题会破坏 ODR。供应商的二进制文件是使用某个类的特定定义编译的,您的二进制文件是使用同一类的不同定义编译的。那是违法的。不管变化多小。定义必须逐个令牌相同,句号。

我建议通过将它们包装在包含的#pragmas 中(或在自定义代理标头中,并包含它)来简单地消除这些标头中的警告。

【讨论】:

UV'd。但是至于“删除显式是否与二进制兼容最终取决于您的编译器,因此您必须在其文档中找到它。”我们在这里是矛盾的。我的理解是explicit不允许影响struct布局。不过可能是错的。 @Bathsheba 关于布局我不知道,但explicit 可能会参与名称修改,并更改构造函数的过程名称。我承认在没有阅读整个标准的情况下说没有任何保证对我来说有点牵强,但我怀疑是否有关于此的部分,所以......安全第一! @Batsheba 摆弄这样的标题会破坏 ODR。供应商的二进制文件是使用某个类的特定定义编译的,您的二进制文件是使用同一类的不同定义编译的。那是违法的。不管变化多小。定义必须逐个令牌相同,句号。据我们所知,编译器可以在符号名称中包含定义的散列。

以上是关于从构造函数二进制文件中删除“显式”是不是兼容?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中为结构读取二进制文件的运行时错误

用于 gzip 和 zip 二进制文件的压缩是不是兼容?

显式默认构造函数

在 C++ 中显式删除移动构造函数的用例 [关闭]

APDU 命令读取二进制命令与文件结构不兼容

访问控制对已删除的构造函数是不是重要?