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

pes*_*che 45 c++ static-members header-only

在非模板库类中拥有静态成员的最佳方法是什么,而不必在类用户上承担定义成员的负担?

说我想提供这个课程:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

public:
    void foo()
    {
        static_resource_.bar();
    }
};
Run Code Online (Sandbox Code Playgroud)

那么类的用户一定不要忘了某处定义静态成员(如已经回答了 很多 ):

// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
Run Code Online (Sandbox Code Playgroud)

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

Mat*_* M. 46

您可以使用函数本地静态变量.

struct Foo
{
    inline static int I = 0;
};
Run Code Online (Sandbox Code Playgroud)

  • @SrinathSridhar:没什么可说的,这只是C++的一个特性.当使用`static`存储限定符声明函数作用域的变量时,则创建一个且仅创建一个实例的语言.第一次流量控制确定性地通过其声明时,此实例是惰性初始化的. (5认同)
  • @MicahCaldwell:谢谢你的评论,我多年没有使用Visual Studio了.这很不幸,因为它在gcc中很长时间都是线程安全的(甚至在C++ 11之前). (4认同)
  • 在C++ 11规范之前,这不是线程安全的.即使现在规范已经出来,但并非所有编译器都支持线程安全的静态初始化.例如,MS Visual Studio 2012或2013都不支持他们所谓的"魔法静态". (3认同)
  • 有人可以解释为什么这有效吗? (2认同)

pes*_*che 18

我自己的解决方案是使用模板化的持有者类,因为静态成员在模板中工作正常,并使用此持有者作为基类.

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

template <typename T>
T static_holder<T>::static_resource_;
Run Code Online (Sandbox Code Playgroud)

现在使用持有者类:

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

class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
    void foo()
    {
        static_resource_.bar();
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,由于成员名称在holder类中指定,因此不能对多个静态成员使用相同的holder.

  • 注意:实际上,您可以使用合成而不是继承.`struct A {static_holder <B> x; static_holder <B> y; `会工作,虽然它不会利用空基优化. (7认同)

小智 5

从C ++ 17开始,您现在可以使用内联变量来执行此操作:

static const inline float foo = 1.25f;
Run Code Online (Sandbox Code Playgroud)