关于标准库模板添加额外默认模板参数的合规性及std::destroy_at实现差异的技术问询
关于标准库模板添加额外默认模板参数的合规性及std::destroy_at实现差异的技术问询
先来看这段让人头疼的代码:
#include <memory> class A { protected: ~A() = default; friend void std::destroy_at<A>(A*); // libstdc++ 编译通过,libc++ 编译失败 public: void f() { std::destroy_at(this); } }; int main() { }
这段代码的奇怪之处在于:它在GCC的libstdc中能正常编译,但换到Clang的libc就直接报错了。问题根源出在两个标准库对std::destroy_at的实现差异上:
- libc++的实现给模板加了一个额外的默认模板参数,用来排除数组类型:
template<typename T, std::enable_if_t<!std::is_array_v<T>, int> = 0> void destroy_at(T*) { ... } - 而C++标准里对
std::destroy_at的定义是没有这个额外参数的简洁版本:template<typename T> void destroy_at(T*) { ... }
那核心问题来了:标准库实现能不能给标准规定的模板添加额外的默认模板参数?这种做法符合C++标准吗?
咱们直接看C++标准的相关规定:标准允许标准库实现为标准模板添加额外的默认模板参数,但有一个硬性要求:这些额外参数不能破坏用户代码的兼容性——也就是说,用户按照标准写法编写的代码,必须能在该实现下正常工作。
回到这个案例:libc给destroy_at加的默认模板参数,导致用户显式指定模板参数的friend声明std::destroy_at<A>(A*)无法匹配到libc的模板(因为libc的模板需要两个模板参数,而用户只指定了一个),这就违反了标准的兼容性要求。所以libc的这个实现其实是不符合标准的,而libstdc++的实现更贴合标准的定义,所以能正常处理用户的代码。
内容来源于stack exchange
相关产品推荐
相关产品推荐

