¿Por qué un miembro de datos estáticos necesita definirse fuera de la clase?

De acuerdo con los miembros de datos estáticos en el centro de conocimiento de IBM C ++:

La statement de un miembro de datos estáticos en la lista de miembros de una clase no es una definición. Debe definir el miembro estático fuera de la statement de clase, en el ámbito del espacio de nombres.

¿Porqué es eso? ¿Cuál es el esquema detrás de eso con respecto a la asignación de memoria?

Es una regla del lenguaje, conocida como la Regla de una sola definición . Dentro de un progtwig, cada objeto estático (si se usa) se debe definir una vez y solo una vez.

Las definiciones de clase suelen ir en archivos de encabezado, incluidos en varias unidades de traducción (es decir, a partir de múltiples archivos de origen). Si la statement del objeto estático en el encabezado fuera una definición, terminarías con múltiples definiciones, una en cada unidad que incluye el encabezado, lo que rompería la regla. Entonces, en cambio, no es una definición, y debes proporcionar exactamente una definición en otro lugar.

En principio, el lenguaje podría hacer lo que hace con las funciones en línea, permitiendo que varias definiciones se consoliden en una sola. Pero no es así, así que estamos atascados con esta regla.

No se trata de la pieza de asignación de memoria en absoluto. Se trata de tener un único punto de definición en una unidad de comstackción vinculada. @Nick también señaló esto.

De la web de Bjarne http://www.stroustrup.com/#in-class

Por lo general, una clase se declara en un archivo de cabecera y, por lo general, un archivo de cabecera se incluye en muchas unidades de traducción. Sin embargo, para evitar reglas de enlazador complicadas, C ++ requiere que cada objeto tenga una definición única. Esa regla se rompería si C ++ permitiera la definición dentro de la clase de las entidades que debían almacenarse en la memoria como objetos.

A partir de C ++ 17 ahora puede definir miembros de datos estáticos dentro de una clase. Ver cppreference :

Un miembro de datos estáticos puede declararse en línea. Un miembro de datos estáticos en línea se puede definir en la definición de clase y puede especificar un inicializador. No necesita una definición fuera de clase:

 struct X { inline static int n = 1; };