c++ 如何在只有头的库中拥有静态数据成员?[副本]

sxpgvts3  于 2023-10-21  发布在  其他
关注(0)|答案(3)|浏览(139)

此问题已在此处有答案

How to initialize static members in the header [duplicate](7个回答)
How can you define a static data member of type const std::string?(11个答案)
How to initialize private static data members in a header file(18回答)
8天前关闭
在非模板化库类中拥有静态成员,而不将定义成员的负担放在类用户身上的最佳方法是什么?
假设我想提供这个类:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

public:
    void foo()
    {
        static_resource_.bar();
    }
};

然后类的用户一定不要忘记在某处定义静态成员(已经是answeredmanytimes):

// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;

下面我有一个答案,但它有一些缺点。是否有更好和/或更优雅的解决方案?

2skhul33

2skhul331#

C++17及以上

使用inline static变量进行非动态初始化:

struct Foo
{
    inline static int I = 0;
};

否则使用函数局部静态变量:

struct Foo
{
    static std::string& Bar()
    {
        static std::string S = compute();
        return S;
    }
};

C++14及以下

使用函数局部静态,因为它们更容易使用。
如果出于某种原因,你真的想要一个静态的 * 数据成员 *,那么你可以使用模板技巧:

template <typename T = void>
struct Foo
{
     static int I = 0; // inline initialization only for simple types.
};

template <typename T>
int Foo<T>::I;

本地静态

对于需要动态初始化的资源,最好使用本地静态。
文件作用域或类作用域静态数据的动态初始化顺序是未定义的,一般来说,当你试图读取一个未初始化的静态数据作为另一个静态数据的初始化的一部分时,会导致静态数据顺序失败。本地静态解决了这个问题,在第一次使用时被惰性地初始化。
然而,使用局部静校正会有一些轻微的开销。从C++11开始,初始化要求是线程安全的,这通常意味着任何访问都由原子读取和良好预测的分支进行门控。

ssm49v7z

ssm49v7z2#

我自己的解决方案是使用一个模板化的保持器类,因为静态成员在模板中工作得很好,并将此保持器用作基类。

template <typename T>
struct static_holder
{
    static T static_resource_;
};

template <typename T>
T static_holder<T>::static_resource_;

现在使用保持器类:

class expensive_resource { /*...*/ };

class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
    void foo()
    {
        static_resource_.bar();
    }
};

但是由于成员的名称是在保持器类中指定的,因此不能对多个静态成员使用同一个保持器。

2nbm6dog

2nbm6dog3#

在C++ 17。你现在可以使用内联变量来实现这一点:

static const inline float foo = 1.25f;

相关问题