c++ - funcion - ¿Cómo ocultar una plantilla auxiliar de implementación?
plantilla de funcion (5)
Dado que el usuario de su código necesita ver la definición completa de la función func1
, su implementación, ni la implementación de la función auxiliar, pueden ocultarse.
Pero si mueve la implementación a otro archivo , el usuario solo tendrá que enfrentarse a la declaración de la plantilla:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
Y la definición:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
Supongamos que tengo dos funciones de plantilla declaradas en un archivo de encabezado:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
Y suponga que la implementación de estas funciones (también en un archivo de encabezado y no en un archivo fuente, porque son plantillas) utiliza alguna función auxiliar de implementación, que también es una plantilla:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
En cualquier archivo fuente que incluya el archivo de encabezado, la función de ayuda estará visible. No quiero eso, porque la función auxiliar es solo un detalle de implementación. ¿Hay alguna manera de ocultar la función de ayuda?
Dos opciones de la parte superior de mi cabeza:
- Mueva toda la implementación a un archivo hpp que incluya al final de su archivo h.
- Refactorice su código como plantillas de clase, luego haga que los ayudantes sean privados.
El precedente establecido es colocar ese tipo de cosas en un espacio de nombres anidado llamado especialmente (es decir, consistentemente). Boost usa los namespace details
, Loki usa el namespace Private
. Obviamente, nada puede impedir que alguien use el contenido de esos espacios de nombres, pero ambos nombres transmiten el significado de que sus contenidos no están destinados al consumo general.
Dicho esto, una alternativa fácil es convertir func1
y func2
de plantillas de función libres en plantillas de función miembro estáticas de alguna clase común; De esta manera, el helper
puede ser simplemente un miembro privado de dicha clase, invisible para el mundo exterior:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Un enfoque común (como se usa en muchas bibliotecas Boost, por ejemplo) es colocar al ayudante en un espacio de nombres llamado details
, posiblemente en un encabezado separado (incluido del encabezado "público").
No hay forma de evitar que sea visible y llamable, pero esto indica claramente que es parte de la implementación, no de la interfaz.
Yo haría (como se dijo antes) hacer una clase de plantilla, hacer que todas las funciones sean estáticas y la función auxiliar sea privada. Pero además de eso, también recomendaría que el constructor sea privado como se muestra a continuación:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
Cuando hace que el constructor sea privado, el compilador no permitirá instancias de esta clase de plantilla. Entonces el código de abajo se volvería ilegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it''s private
Foo<int> foo_instance; //not allowed, because it''s private
}
Entonces, ¿por qué alguien querría esto? Porque tener instancias diferentes que son EXACTAMENTE iguales es algo que probablemente nunca querrás. Cuando el compilador le dice que el constructor de alguna clase es privado, entonces puede asumir que tener instancias diferentes sería innecesario.