简体   繁体   English

如何在仅标头库中拥有静态数据成员?

[英]How to have static data members in a header-only library?

What is the best way to have a static member in a non-templated library class, without placing the burden of defining the member on the class user?在非模板化库类中拥有静态成员的最佳方法是什么,而不会将定义成员的负担放在类用户身上?

Say I want to provide this class:说我想提供这个类:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

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

Then the user of the class must not forget to define the static member somewhere (as already answered many times ):然后类的用户一定不要忘记在某处定义静态成员(已经多次回答

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

I do have an answer below, but it has some disadvantages.我在下面确实有一个答案,但它有一些缺点。 Are there better and/or more elegant solutions?是否有更好和/或更优雅的解决方案?

C++17 and above C++17及以上

Use inline static variables for non-dynamic initialization:使用inline static变量进行非动态初始化:

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

And use function local static variables otherwise:否则使用函数局部静态变量:

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

C++14 and below C++14及以下

Use function local statics, as they are plain easier to use.使用函数局部静态,因为它们更容易使用。

If for some reason you really wish for a static data member , then you can use the template trick:如果出于某种原因你真的想要一个静态数据成员,那么你可以使用模板技巧:

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

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

On local statics关于局部静力学

For resources which require dynamic initialization, it is best to use a local static.对于需要动态初始化的资源,最好使用局部静态。

The order in which file-scope or class-scope statics are dynamically initialized is undefined, in general, leading to the Static Initialization Order Fiasco when you try to read a uninitialized static as part of the initialization of another.动态初始化文件范围或类范围静态的顺序是未定义的,通常,当您尝试读取未初始化的静态作为另一个初始化的一部分时,会导致静态初始化顺序 Fiasco。 Local static solve the issue by being initialized lazily, on first use.本地静态通过在首次使用时延迟初始化来解决问题。

There is some slight overhead to using local statics, however.然而,使用局部静态有一些轻微的开销。 From C++11 onwards, the initialization is required to be thread-safe, which typically means that any access is gated by an atomic read and well-predicted branch.从 C++11 开始,初始化要求是线程安全的,这通常意味着任何访问都由原子读取和预测良好的分支来控制。

My own solution is to use a templated holder class, as static members work fine in templates, and use this holder as a base class.我自己的解决方案是使用模板化的持有者类,因为静态成员在模板中工作良好,并将此持有者用作基类。

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

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

Now use the holder class:现在使用 holder 类:

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

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

But as the name of the member is specified in the holder class, you can't use the same holder for more than one static member.但是由于成员的名称是在 holder 类中指定的,所以不能对多个静态成员使用同一个 holder。

As of C++ 17. You can now use inline variables to do this:从 C++ 17 开始。您现在可以使用内联变量来执行此操作:

static const inline float foo = 1.25f;

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

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