简体   繁体   English

声明不变的 static “默认”成员变量/函数的“正确”方法是什么?

[英]What is the "correct" way to declare non-changing, static "default" member variables/functions?

Given a simple, bare-bone, Vector3D example.给定一个简单的、基本的 Vector3D 示例。 How would one define static default "values", such that vec3<T>::ones (or vec3<T>::ones() ) provides a vec3<T>{T{1}, T{1}, T{1}} .如何定义 static 默认“值”,以便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}; }();

};

I've commonly seen variations of the three options, and I have a few questions whether or not my understanding on this matter is correct:我经常看到这三个选项的变体,我有几个问题我对这个问题的理解是否正确:

  • Option 1, to my understanding, serves as a "factory function" creating new vec3 instances for each invocation.根据我的理解,选项 1 充当“工厂函数”,为每次调用创建新的 vec3 实例。 Is this equivalent to any caller using the vec3{e0, e1, e2} directly?这是否等同于任何调用者直接使用vec3{e0, e1, e2}

  • Option 2 creates one vec3 instance exactly once, the very first time the function is executed.选项 2 只创建一个 vec3 实例一次,即第一次执行 function 时。 Therefore, the compiler is required to make use of a synchronization primitive to ensure that static initialization happens exactly once.因此,编译器需要使用同步原语来确保 static 初始化恰好发生一次。 Do all future invocations simply return "the locally cached" value without any synchronization primitives?是否所有未来的调用都只返回“本地缓存的”值而没有任何同步原语?

  • Option 3 creates a static inline member variable at compile time, I think?选项 3 在编译时创建一个 static 内联成员变量,我想? GCC allows the static inline variable to be declared as constexpr (which is why I believe everything happens at compile time), whereas clang only compiles with const (which does not guarantee compile time instantiation of the static member variable?). GCC 允许将 static 内联变量声明为constexpr (这就是为什么我相信一切都发生在编译时),而 clang 仅使用const进行编译(这不保证 static 成员变量的编译时实例化?)。

Are there any other differences between these solutions that I am missing and should I prefer any?我缺少的这些解决方案之间是否还有其他差异,我应该更喜欢这些差异吗? Are there any other ways to declare static members at compile time?还有其他方法可以在编译时声明 static 成员吗?

You can look at how it's done in the standard for std::strong_ordering :你可以看看它是如何在std::strong_ordering的标准中完成的:

class strong_ordering {
    // ...
public:
    // valid values
    static const strong_ordering less;
    static const strong_ordering equal;
    static const strong_ordering equivalent;
    static const strong_ordering greater;
    // ...
};
// valid values' definitions
inline constexpr strong_ordering strong_ordering::less(ord::less);
inline constexpr strong_ordering strong_ordering::equal(ord::equal);
inline constexpr strong_ordering strong_ordering::equivalent(ord::equivalent);
inline constexpr strong_ordering strong_ordering::greater(ord::greater);

So the strategy is static const declaration (without initializer) in the class, then inline constexpr definition (with initializer) outside the class to guarantee compile-time initialization and allow the variable to be used in constant expressions.所以策略是 class 中的static const声明(无初始化器),然后在 class 外inline constexpr定义(带初始化器)以保证编译时初始化并允许变量在常量表达式中使用。

The reason why the declaration and definition need to be separated is that inside the class definition, the class is incomplete, and you can't have a static member definition with an incomplete type.声明和定义需要分开的原因是在class定义里面,class是不完整的,不能有不完整类型的static成员定义 Having a static constexpr data member in the class is defining it.在 class 中有一个static constexpr数据成员正在定义它。 ( inline is implied on such declarations.) So you have to have a non-defining declaration inside the class, and then a defining declaration later on after the class is complete. inline隐含在此类声明中。)因此,您必须在 class 中有一个非定义声明,然后在 class 完成之后再定义一个声明。 In the defining declaration (the definition), you can use constexpr .在定义声明(定义)中,您可以使用constexpr

So in your case it would look like this:所以在你的情况下它看起来像这样:

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) 
    { }

    static const vec3 ones;
};

template <class T>
inline constexpr vec3<T> vec3<T>::ones = {1, 1, 1};

In this case because vec3 is a template, I think you don't even need inline .在这种情况下,因为vec3是一个模板,我认为你甚至不需要inline

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM