variable usar programacion funcion estaticas estatica ejemplos cuando c++ templates static

c++ - usar - Variable estática dentro de la función de plantilla



variable static c# (7)

En C ++, si define esta función en header.hpp

void incAndShow() { static int myStaticVar = 0; std::cout << ++myStaticVar << " " << std::endl; }

e incluye header.hpp en al menos dos archivos .cpp. Entonces tendrás multiple definition of incAndShow() . Lo que se espera. Sin embargo, si agrega una plantilla a la función

template <class T> void incAndShow() { static int myStaticVar = 0; std::cout << ++myStaticVar << " " << std::endl; }

entonces no tendrás ninguna multiple definition of error. Del mismo modo, dos .cpp diferentes que llamen a la función con la misma plantilla (por ejemplo, incAndShow<int>() ) compartirán myStaticVar . ¿Esto es normal? Estoy haciendo esta pregunta porque confío en esta "característica" (compartiendo la variable estática) y quiero estar seguro de que no es solo mi implementación la que hace esto.


La diferencia al crear la plantilla de función es que tiene un enlace externo. El mismo incAndShow será accesible desde todas las unidades de traducción.

Parafraseo del borrador de trabajo estándar de C ++ N2798 (2008-10-04): 14 parte 4: una plantilla de función no miembro puede tener enlace interno, otros siempre tienen enlace externo. 14.8 punto 2: cada especialización tendrá su propia copia de la variable estática.

Su plantilla de función debe tener un enlace externo a menos que lo declare en el espacio de nombres sin nombre o algo así. Por lo tanto, para cada T que use con su plantilla de función, debe obtener una variable estática utilizada para el rendimiento del programa. En otras palabras, está bien confiar en tener solo una variable estática en el programa para cada creación de instancias de la plantilla (una para T == int, una para T == corta, etc.).

Además, esto puede llevar a situaciones extrañas si define incAndShow de manera diferente en diferentes unidades de traducción. Por ejemplo, si lo define para que se incremente en un archivo y la disminución en otro (sin especificar el enlace interno al poner la función en el espacio de nombres sin nombre), ambos terminarán compartiendo la misma función, que se elegirá al azar en el momento de la compilación. (con g ++ depende del orden en que se dan los archivos de objetos en la línea de comandos).


Las plantillas se crean instancias según sea necesario, lo que significa que el compilador (¿el vinculador también en este caso?) Se asegurará de que no termine con varias instancias de la misma plantilla, así como solo las instancias de plantillas que necesite, en su solo caso incAndShow<int>() se incAndShow<int>() instancia y nada más (de lo contrario, el compilador tendría que intentar crear una instancia para cada tipo que no tenga sentido).

Por lo tanto, asumo que los mismos métodos que utiliza para averiguar para qué tipo crear una instancia de la plantilla impide que se incAndShow<int>() una instancia dos veces para el mismo tipo, por ejemplo, solo una instancia de incAndShow<int>()

Esto es diferente del código no de plantilla.


Puedes confiar en esto. La ODR (Regla de una definición) dice en 3.2/5 en el Estándar, donde D representa la plantilla de función no estática (fuente cursiva por mí)

Si D es una plantilla y se define en más de una unidad de traducción, los últimos cuatro requisitos de la lista anterior se aplicarán a los nombres del alcance de la plantilla que se utiliza en la definición de la plantilla (14.6.3), y también a los nombres dependientes En el punto de instanciación (14.6.2). Si las definiciones de D satisfacen todos estos requisitos, entonces el programa se comportará como si hubiera una definición única de D. Si las definiciones de D no satisfacen estos requisitos, entonces el comportamiento no está definido.

De los últimos cuatro requisitos, los dos más importantes son aproximadamente

  • Cada definición de D consistirá en la misma secuencia de fichas.
  • los nombres en cada definición se referirán a las mismas cosas ("entidades")

Editar

Me imagino que esto solo no es suficiente para garantizar que sus variables estáticas en las diferentes instancias sean todas iguales. Lo anterior solo garantiza que las definiciones múltiples de la plantilla son válidas. No dice nada sobre las especializaciones generadas a partir de él.

Aquí es donde se activa el enlace . Si el nombre de una especialización de plantilla de función (que es una función) tiene un enlace externo ( 3.5/4 ), entonces un nombre que se refiere a dicha especialización se refiere a la misma función. Para una plantilla que se declaró estática, las funciones instanciadas desde ella tienen vínculos internos, debido a

Las entidades generadas a partir de una plantilla con enlace interno son distintas de todas las entidades generadas en otras unidades de traducción. -- 14/4

Un nombre que tenga un ámbito de espacio de nombres (3.3.6) tiene un enlace interno si es el nombre de un objeto, [...] referencia, función o plantilla de función que se declara explícitamente como estático -- 3.5/3

Si la plantilla de función no fue declarada con estática, entonces tiene un enlace externo (que, por cierto, también es la razón por la que tenemos que seguir el ODR en absoluto. De lo contrario, D no se definiría en absoluto!). Esto puede derivarse de 14/4 (junto con 3.5/3 )

Una plantilla de función no miembro puede tener vinculación interna; Cualquier otro nombre de plantilla tendrá un enlace externo. -- 14/4 .

Finalmente, llegamos a la conclusión de que una especialización de plantilla de función generada a partir de una plantilla de función con enlace externo tiene un enlace externo de 3.5/4 :

Un nombre que tenga un ámbito de espacio de nombres tiene un enlace externo si es el nombre de una [...] función, a menos que tenga un enlace interno -- 3.5/4

Y cuando tiene un enlace interno, se explicó en 3.5/3 para funciones proporcionadas por especializaciones explícitas, y 14/4 para especializaciones generadas (ejemplificaciones de plantillas). Dado que el nombre de su plantilla tiene enlace externo, todas sus especializaciones tienen enlace externo: si usa su nombre ( incAndShow<T> ) de diferentes unidades de traducción, se referirán a las mismas funciones, lo que significa que sus objetos estáticos serán iguales en cada una. ocasión.


Sí, es "normal", pero cualquier cosa que intentes lograr con esta "característica" quizás sea cuestionable. Trate de explicar por qué quiere usar una variable estática local, puede ser que podamos encontrar una forma más limpia de hacerlo.

La razón por la que esto es normal se debe a la forma en que se compilan y vinculan las funciones de la plantilla. Cada unidad de traducción (las dos .cpp en su caso) obtiene su propia copia de incAndShow y cuando el programa está enlazado, las dos incAndShow se fusionarán en una sola. Si declara su función normal en línea en el archivo de encabezado, obtendrá un efecto similar.


Solo así entiendo tu pregunta. Está preguntando si es normal que cada versión de la función de plantilla tenga su propia instancia de myStaticVar. (por ejemplo: incAndShow<int> vs. intAndShow<float> La respuesta es sí.

Su otra pregunta es, si dos archivos incluyen el encabezado que contiene la función de plantilla, ¿seguirán compartiendo la variable estática para una T. dada? Yo diría que sí.


Tomemos este ejemplo que muestra que el comportamiento es absolutamente esperado:

#include <iostream> template <class T> class Some { public: static int stat; }; template<class T> int Some<T>::stat = 10; void main() { Some<int>::stat = 5; std::cout << Some<int>::stat << std::endl; std::cout << Some<char>::stat << std::endl; std::cout << Some<float>::stat << std::endl; std::cout << Some<long>::stat << std::endl; }

Obtienes: 5 10 10 10 10

Lo anterior muestra que el cambio en la variable estática es solo para el tipo "int" y, por lo tanto, en su caso no ve ningún problema.


  • las plantillas solo se convertirán realmente en código una vez que se crean instancias (es decir, se usan)
  • Los encabezados no se deben usar para el código de implementación, sino solo para declaraciones