Pregunta

¿Cuál es la mejor manera de tener un miembro estático en un no-con plantilla de biblioteca de clase, sin la colocación de la carga de la definición de los miembros de la clase de usuario?

Dicen que quieren ofrecer esta clase:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

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

A continuación, el usuario de la clase no debe olvidar para definir el miembro estático en algún lugar (como ya respondió muchos veces):

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

Yo tengo una respuesta, pero tiene algunas desventajas.Hay mejores y/o más soluciones elegantes?

¿Fue útil?

Solución

C++17 y por encima de

Uso inline static variables para los no-inicialización dinámica:

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

Y el uso de la función local de las variables estáticas de otra manera:

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

C++14 y siguientes

Uso de la función local de la estática, ya que son simplemente más fácil de usar.

Si por alguna razón usted realmente desea para una estática miembro de datos, entonces usted puede utilizar la plantilla truco:

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

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

En el local de la estática

Por los recursos que requieren inicialización dinámica, es mejor utilizar un local estática.

El orden en que archivo-ámbito de aplicación o de clase-ámbito de aplicación de la estática son dinámicamente inicializado no está definido, en general, conduce a la Inicialización Estática Orden Fiasco cuando intenta leer un sin inicializar estática como parte de la inicialización de otro.Local estática de resolver el problema por ser inicializado perezosamente, en el primer uso.

Hay algunos leve sobrecarga de uso de locales de la estática, sin embargo.A partir de C++11 en adelante, la inicialización se requiere ser seguro para subprocesos, lo que normalmente significa que el acceso está cerrado por un átomo de leer y bien predijo rama.

Otros consejos

Mi propia solución es usar una clase de titular plantelada, ya que los miembros estáticos funcionan bien en plantillas y usan este soporte como una clase base.

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

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

Ahora use la clase de titular:

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

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

Pero, como se muestra el nombre del miembro en la clase de titular, no puede usar el mismo soporte para más de un miembro estático.

A partir de C ++ 17. Ahora puede usar variables en línea para hacer esto:

static const inline float foo = 1.25f;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top