败犬日报 2025-07-13
1. C++ 各种初始化比较(图)
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 源码。