sirven - template typename t c++
¿Cómo crear una instancia explícita de una plantilla para todos los miembros del vector MPL en C++? (6)
Hace poco tuve el mismo requisito y obtuve buenos resultados con una simple creación de instancias de plantilla de funciones:
template <class... T>
void forceInstantiation(typedef boost::mpl::vector<T...>*) {
using ex = int[];
(void)ex{(void(&Foo::read<T>), 0)..., 0};
// C++17
// (void)((void(&Foo::read<T>), ...));
}
template void forceInstantiation(types*);
Considere el siguiente archivo de encabezado:
// Foo.h
class Foo {
public:
template <typename T>
void read(T& value);
};
Quiero crear una instancia explícita de la plantilla de función miembro Foo::read
en un archivo fuente para todos los tipos incluidos en un boost::mpl::vector
:
// Foo.cc
#include <boost/mpl/vector.hpp>
#include <boost/mpl/begin_end.hpp>
#include "Foo.h"
template <typename T>
void Foo::read(T& value) { /* do something */ }
typedef boost::mpl::vector<int, long, float> types;
// template Foo::read<int >(int&);
// template Foo::read<long >(long&);
// template Foo::read<float>(float&);
// instantiate automatically ???
¿Es posible? Gracias de antemano, Daniel.
EDITAR
Encontré alguna solución. Parece que al asignar un puntero a Foo::read<T>
en el constructor de una estructura, de la cual se declara la variable, se genera una instanciación:
// intermezzo
template <typename T> struct Bar {
Bar<T>() {
void (Foo::*funPtr)(T&) = &Foo::read<T>;
}
};
static Bar<int > bar1;
static Bar<long > bar2;
static Bar<float> bar3;
Entonces el proceso puede ser automatizado de la siguiente manera:
// Foo.cc continued
template <typename B, typename E>
struct my_for_each {
my_for_each<B, E>() {
typedef typename B::type T; // vector member
typedef void (Foo::*FunPtr)(T&); // pointer to Foo member function
FunPtr funPtr = &Foo::read<T>; // cause instantiation?
}
my_for_each<typename boost::mpl::next<B>::type, E> next;
};
template<typename E>
struct my_for_each<E, E> {};
static my_for_each< boost::mpl::begin<types>::type,
boost::mpl::end<types>::type > first;
¿Pero no sé si esta solución es portátil y cumple con los estándares? (Funciona con compiladores Intel y GNU).
La creación de instancias explícita tiene una gramática especial y un significado especial que cumplir, por lo que no se puede hacer con la programación meta.
su solución causa una instanciación, pero no una instanciación explícita.
No creo que sea necesario, ni es posible.
Puede usar directamente (llamar) la función Foo: read (barra), para la barra variable de cualquier tipo, siempre que el tipo esté bien definido en la implementación de la función de plantilla. El compilador automáticamente transformará su argumento en el tipo "T".
Por ejemplo:
template <class T>
Foo::read(T & var)
{
std::cin >> var;
}
T está bien definido cuando T es un tipo de transmisión compatible con cin.
El ejemplo será independiente, si se elimina "Foo ::". Quiero decir, para "Foo ::", deberías haber definido en algún lugar una clase Foo, o un espacio de nombres Foo, para que funcione.
Sin embargo, tenga en cuenta que la plantilla siempre debe ir dentro de un archivo .h, no un archivo .cpp (solo busque en la web con la palabra clave "la plantilla c ++ no se puede implementar en el archivo cpp"
No estoy seguro de si esta es la solución a su problema, pero quizás pueda hacerlo con una especialización de plantillas.
Nueva cabecera:
// Foo.h
template < typename T >
struct RealRead;
class Foo {
public:
template <typename T>
void read(T& value);
};
template <typename T>
void Foo::read(T& value)
{
RealRead< T >::read( value );
}
Nueva fuente :
template < >
struct RealRead< int >
{
static void read( int & v )
{
// do read
}
};
template < >
struct RealRead< float >
{
static void read( float & v )
{
// do read
}
};
//etc
// explicitly instantiate templates
template struct RealRead< int >;
template struct RealRead< float >;
Puede crear una instancia explícita de Foo para un parámetro de plantilla T dado con template class Foo<T>;
En cuanto a la creación de instancias por lotes, no creo que sea posible. Tal vez con las plantillas variadas es posible crear una clase de instancia, de modo que algo como la Instantiate<Foo, int, short, long, float, etc>
crearía las plantillas adecuadas, pero aparte de eso, debe recurrir a la creación de instancias manual.
Si pretende utilizar su clase solo en un único módulo (es decir, no lo exportará) puede usar boost / mpl / for_each. La función de plantilla definida de esta manera (usando mpl / for_each) no se exportará (incluso si declara __declspec (exportar) antes del nombre de la clase o la firma de la función):
// Foo.cpp
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
template<class T>
void read(T& value)
{
...
}
using types = boost::mpl::vector<long, int>;
//template instantiation
struct call_read {
template <class T>
void operator()(T)
{
T t; //You should make sure that T can be created this way
((Foo*)nullptr)->read<T>(t); //this line tells to compiler with templates it should instantiate
}
};
void instantiate()
{
boost::mpl::for_each<types>(call_read());
}
Si necesita exportar / importar su estructura y métodos de plantilla, hay una solución que utiliza boost / preprocesador.
// Foo.h
#ifdef <preprocessor definition specific to DLL>
# define API __declspec(dllexport)
#else
# define API __declspec(dllimport)
#endif
class API Foo {
public:
template<class T> void read(T& value);
};
// Foo.cpp
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/mpl/vector.hpp>
template<class T>
void read(T& value)
{
...
}
//using this macro you can define both boost::mpl structure AND instantiate explicitly your template function
#define VARIANT_LIST (std::wstring)(long)(int)
using types = boost::mpl::vector<BOOST_PP_SEQ_ENUM(VARIANT_LIST)>;
//Here we should use our API macro
#define EXPLICIT_INSTANTIATION(r, d, __type__) /
template API void Foo::read<__type__>(__type__&);
BOOST_PP_SEQ_FOR_EACH(EXPLICIT_INSTANTIATION, _, VARIANT_LIST)
Si no necesita esta funcionalidad adicional, la primera solución es mucho más limpia, supongo.