Tengo curiosidad por saber si es posible garantizar en tiempo de compilación que un método se llame exactamente en un lugar.
Tenga en cuenta que está bien si la función se llama más de una vez (por ejemplo, en un bucle), pero no se debe llamar en dos bucles separados.
Esto se puede dividir en dos partes, también estoy interesado en las soluciones que cubren cualquiera de las partes:
(a) asegurar que se llame a un método en al menos un lugar
(b) asegurar que se llame a un método en un lugar como máximo
Tengo control total sobre la estructura del código, y son bienvenidos diferentes modismos que logran la misma idea.
// class.h
class MyClass {
public:
void my_method();
}
Lo siguiente no debe compilarse (nunca llamado)
#include "class.h"
int main() {
MyClass my_class;
}
Lo siguiente no debe compilarse (llamado en más de un lugar)
#include "class.h"
int main() {
MyClass my_class;
my_class.my_method();
while(true) {
my_class.my_method();
}
}
Lo siguiente debe compilarse (llamado exactamente en un lugar):
#include "class.h"
int main() {
MyClass my_class;
while(true) {
my_class.my_method();
}
}
__COUNTER__
macro no estándar para hacer esto. Algo así comostatic_assert(__COUNTER__ == 0); my_class.my_method();
. Sin embargo, el contador se reinicia en cada unidad de traducción, por lo que solo puede verificar que la función se llame una vez por unidad de traducción.Respuestas:
Enfoque de baja tecnología:
Dado que tiene control sobre la estructura del código (que incluye el sistema de compilación, supongo), aquí hay una solución de baja tecnología:
Alternativamente:
Si realmente quieres resolverlo con C ++, entonces puedes intentar
Sin embargo, los contadores de tiempo de compilación son magia negra (dice I, y realmente me gusta TMP), y forzar violaciones de ODR para este propósito parece un vudú similar (al menos requeriría un caso de prueba que no se vincule).
Pero en serio:
No hagas esto. Hagas lo que hagas, puede pervertirse casi sin esfuerzo mediante una función de envoltura:
MyClass::my_method()
se llama solo en el contenedor. Todos los demás simplemente llaman al reiniciador, que probablemente incluso está compilado por el compilador.Como otros sugirieron: podría ser mucho más útil si explicas lo que estás tratando de hacer.
fuente
Aquí hay una idea aproximada que puede funcionar (demasiado tiempo para un comentario, pero incompleta para una buena respuesta SO).
Puede lograr esto contando / verificando las instancias de plantillas.
Las plantillas se instancian solo con el uso .
De manera similar, los cuerpos de método / función de plantilla no se analizan ni compilan ni vinculan (más allá de garantizar una sintaxis válida) si nunca se llaman. Esto significa que no se realizan instancias dentro de sus cuerpos).
Es posible que pueda crear una plantilla que mantenga un recuento global de instancias y una afirmación estática sobre eso (o algún otro mecanismo TMP para verificar instancias pasadas).
fuente
Hay una solución parcial a esta pregunta utilizando el preprocesador C y el ensamblaje en línea GNU:
Archivo de encabezado
a.h
:Archivo de implementación
a.cc
:Esta solución es parcial en el sentido de que no impide que el programa llame al método que comienza con el guión bajo directamente sin usar la macro de contenedor.
fuente
Use un contador constexpr. Hay una implementación en otra pregunta
fuente