C++标准是否规定翻译单元内类模板实例化及unique_id调用顺序?
C++编译期计数器的调用顺序问题
背景
在Stack Overflow上有一个针对《C++是否支持编译期计数器》问题的解决方案,该方案借助类模板中的友元函数生成机制,通过unique_id()元函数在编译时生成唯一标识符。
以下是用于说明问题的示例代码:
template <int N> struct A { static constexpr int id = N; }; template <int N> struct B { static constexpr int id = N; }; template <typename T> void foo(); foo<A<unique_id()>>(); // 实例化1 foo<B<unique_id()>>(); // 实例化2 void func() { struct C { static constexpr int id = unique_id(); }; // 实例化3 struct D { static constexpr int id = unique_id(); }; // 实例化4 }
问题
C++标准是否保证单个翻译单元内所有unique_id()调用及相关模板实例化都遵循特定、可预测的顺序?
回答
C++标准没有明确保证这类基于友元注入实现的unique_id()调用顺序,以及对应的模板实例化顺序是严格按代码书写顺序执行的。
原因在于:
- 模板实例化和常量表达式求值的顺序在C++标准中属于未指定行为,编译器有权在满足程序语义的前提下调整这些操作的顺序——比如为了优化编译过程延迟或重排实例化步骤,这会导致
unique_id()生成的标识符顺序可能和代码书写顺序不一致。 - 对于函数内部的局部类(如示例中的C、D),其静态常量成员的初始化顺序,标准同样没有强制要求必须和类定义的顺序严格对应,只要每个初始化操作都是合法的常量表达式即可。
简言之,单个翻译单元内unique_id()的调用及相关模板实例化的顺序不被标准保证为可预测或按代码顺序执行,这类实现本质属于编译器扩展,不同编译器、甚至同一编译器的不同优化等级都可能带来不同的表现。
内容的提问来源于Stack Exchange,提问作者Sergey Kolesnik
相关产品推荐
相关产品推荐

