给出一个简单的、最基本的Vector3D示例,如何定义静态默认“值”,例如vec3<T>::ones
(或vec3<T>::ones()
)提供vec3<T>{T{1}, T{1}, T{1}}
。
template <class T>
struct vec3 {
using value_type = T;
value_type x{}, y{}, z{};
constexpr vec3(const value_type e0, const value_type e1, const value_type e2) noexcept
: x(e0)
, y(e1)
, z(e2)
{ }
// Option 1
[[nodiscard]] constexpr static inline vec3 zeros() noexcept { return {0, 0, 0}; }
// Option 2
[[nodiscard]] constexpr static inline vec3 x_axis() noexcept {
constexpr static vec3 _x_axis{1, 0, 0};
return _x_axis;
}
// Option 3
const static inline vec3 ones = [](){ return vec3{1, 1, 1}; }();
};
我经常看到这三种选择的变体,我有几个问题,我对这个问题的理解是否正确:
- 选项1,据我所知,作为一个“工厂函数”为每次调用创建新的vec3示例,这是否等同于任何调用者直接使用
vec3{e0, e1, e2}
? - 选项2只创建一个vec3示例一次,也就是函数第一次执行的时候。因此,编译器需要使用同步原语来确保静态初始化只发生一次。是否所有未来的调用都只返回“本地缓存”的值,而没有任何同步原语?
- 选项3在编译时创建一个静态内联成员变量,我认为GCC允许静态内联变量声明为
constexpr
(这就是为什么我相信一切都发生在编译时),而clang只使用const
编译(这不保证静态成员变量的编译时示例化?)。
这些解决方案之间是否还有我所遗漏的其他差异,我是否应该更喜欢这些差异?是否有其他方法可以在编译时声明静态成员?
1条答案
按热度按时间72qzrwbm1#
你可以看看
std::strong_ordering
标准是如何实现的:因此策略是在类中声明
static const
(不带初始化器),然后在类外定义inline constexpr
(带初始化器),以保证编译时初始化,并允许在常量表达式中使用变量。声明和定义需要分开的原因是,在类定义内部,类是不完整的,你不能有一个类型不完整的静态成员 definition,让一个
static constexpr
数据成员 in 类就是定义它。(inline
隐含在这样的声明中。)因此,必须在类中有一个非定义声明,然后在类完成后定义声明,在定义声明(定义)中,可以使用constexpr
。在你的例子中,它看起来像这样:
在本例中,因为
vec3
是一个模板,所以我认为您甚至不需要inline
。