如果此代码无法在 C++17 中编译
Should this code fail to compile in C++17?
我正在更新一个项目以使用 C++17,并发现了一些遵循此模式的代码在最新版本的 clang 上导致编译错误的实例:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
{
void operator()(int) const { }
};
int main()
{
boost::variant<int> v = 0;
boost::apply_visitor(vis{}, v);
}
在 C++17 模式下使用 clang v8.0,此操作失败并显示以下错误:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis{}, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
但是,它在 C++14 模式下干净地编译。我发现如果我将大括号初始化vis{}
更改为括号vis()
,那么它在两种模式下都可以正确编译。我尝试过的每个版本的 gcc 都允许在 C++17 模式下同时使用这两种变体。
这是从 C++14 到 C++17 的正确行为变化,还是这是一个叮当错误?如果它是正确的,为什么它现在在 C++17 中无效(或者可能一直都是,但 clang 只允许在早期的标准修订版中这样做(?
clang 在这里是正确的。下面是一个简化的示例:
struct B {
protected:
B() { }
};
struct D : B { };
auto d = D{};
在 C++14 中,D
不是聚合,因为它有一个基类,所以D{}
是"正常"(非聚合(初始化,它调用D
的默认构造函数,而默认构造函数又调用B
的默认构造函数。这很好,因为D
可以访问B
的默认构造函数。
在 C++17 中,聚合的定义被扩大 - 现在允许基类(只要它们是非virtual
的(。 D
现在是一个聚合,这意味着D{}
是聚合初始化。在聚合初始化中,这意味着我们(调用方(正在初始化所有子对象 - 包括基类子对象。但是我们无法访问B
的构造函数(它是protected
(,所以我们不能调用它,所以它的格式不正确。
不用担心,修复很容易。使用括号:
auto d = D();
这又回到了像以前一样调用D
的默认构造函数。
相关文章:
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 代码块中无序多集的编译错误17.12
- 使用 C++17 编译特征需要_SILENCE_CXX17_NEGATORS_DEPRECATION_WARNING定义
- 如何使用msbuild和设置C++17命令行编译Visual Studio项目?
- clang C++17 std::vector over align type 使用 -mavx 编译时元素 SIGSE
- C++17:在编译时将类型映射到整数值
- 为什么 'std::unary_function' 仍然在 c++17 中编译?
- c++17在编译时将带有已删除复制构造函数的类添加到std::vector
- 无法编译简单的C++17程序
- 在 RedHat Linux Enterprise Developer Workstation 上编译 C++17 代码
- 有没有办法在 C++17 中创建编译时类型映射以进行类型检查?
- 使用 C++17,如何创建类型到值的编译时图?
- C++17 在逗号上拆分 constexpr 字符串并在编译时有元素的数量?
- 使用 CLion、CMake 和 VS2017 编译器编译 C++17
- 为什么 GCC 和 clang 之间编译的 c++17 lambda 存在差异?
- gcc 可以使用较旧的第三方库编译 C++17 代码吗?
- 在使用 -std=c++17 编译时在 GCC 中复活 std::auto_ptr
- 如何在编译时检测C 17中是否没有虚拟基础
- 当我击中不良的constexpr时,请停止Visual Studio 17编译
- 使用ld: __stack_chk_guard@@GLIBC_2.17编译错误