Skip to content

败犬日报 2025-07-13

1. C++ 各种初始化比较(图)

img

2. clang constexpr 过早实例化的问题

cpp
#include <memory>

struct B;

struct A {
    std::unique_ptr<B> b = nullptr;
};

struct B {};

这个代码在 clang -std=c++23 报错,把标准降到 20 不会。

这是 clang 的一个老问题,std::unique_ptr<B> 的析构函数在 C++23 变成了 constexpr,在 struct B {}; 前实例化(过早实例化),于是要求 B 是一个完整类型。这也能解释 20 前就不会报错。

有些编译器把函数模板实例化放到 TU(翻译单元)结束,也就是 struct B {}; 后,这样可以不报错。不过这是个 IFNDR (ill-formed no diagnostic required),实例化位置和顺序标准显然没有规定的。ref https://timsong-cpp.github.io/cppwp/n4659/temp.point#8

一个几乎一样的问题:https://github.com/llvm/llvm-project/issues/111185

但是还有一个现象是 std::unique_ptr<B> b = nullptr; 改成 std::unique_ptr<B> b{nullptr}; 就不会报错了。虽然两者选择的都是 unique_ptr(nullptr_t) 构造函数(为什么 = 没有复制,因为 C++17 强制复制消除),但是 clang 实现有细微区别,多了个隐式转换,{} 不接受类型窄化就不需要。具体还得看 clang 源码。