plantillas - template en c++ pdf
EspecializaciĆ³n en plantillas C++ sin funciĆ³n por defecto. (5)
Tengo el siguiente código que compila y funciona bien:
template<typename T>
T GetGlobal(const char *name);
template<>
int GetGlobal<int>(const char *name);
template<>
double GetGlobal<double>(const char *name);
Sin embargo quiero eliminar la función "por defecto". Es decir, quiero hacer todas las llamadas a GetGlobal <t> donde ''t'' no es un int o un doble error.
Por ejemplo, GetGlobal <char> () debería ser un error de tiempo de compilación.
Intenté simplemente eliminar la función predeterminada, pero, como me imaginaba, recibí muchos errores ... Entonces, ¿hay una manera de "deshabilitarla" y permitir llamadas solo a las versiones especializadas de la función?
¡Gracias!
Aunque es una pregunta antigua y obsoleta, vale la pena señalar que C++11
resolvió este problema usando funciones eliminadas:
template<typename T>
T GetGlobal(const char *name) = delete;
template<>
int GetGlobal<int>(const char *name);
ACTUALIZAR
Esto no se compilará bajo MacOS llvm 8
. Se debe a un defecto de 4 años que sigue colgando (consulte este informe de error ).
La siguiente solución se ajustará al problema (utilizando una construcción static_assert
).
template<typename T>
T GetGlobal(const char *name) {
static_assert(sizeof(T) == 0, "Only specializations of GetGlobal can be used");
}
template<>
int GetGlobal<int>(const char *name);
Las siguientes son técnicas alternativas al uso de boost:
Declara un typedef a un nombre dependiente
Esto funciona porque la búsqueda de nombre para DONT solo ocurre cuando se ha reemplazado ''T''. Esta es una versión similar (pero legal) del ejemplo dado por Kirill
template <typename T>
T GetGlobal (const char * name) {
typedef typename T::DONT CALL_THIS_FUNCTION;
}
Utilice un tipo de retorno incompleto
Esta técnica no funciona para especializaciones, pero funcionará para sobrecargas. La idea es que es legal declarar una función que devuelve un tipo incompleto, pero no llamarla:
template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);
Para obtener un error en tiempo de compilación implementarlo como:
template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
Si usas Boost, podrías hacerlo más elegante:
template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
C ++ Standard garantiza que no hay ningún tipo de tipo que tenga un tamaño de 0 igual a 0, por lo que obtendrá un error en tiempo de compilación.
Como sbi sugirió en sus comentarios, el último podría reducirse a:
template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
Prefiero la primera solución, porque da un mensaje de error más claro (al menos en Visual C ++) que los otros.
Si no lo implementas, al menos obtendrás un error de vinculador. Si desea un error en tiempo de compilación, puede hacer esto con las plantillas de clase:
template<typename T>
struct GlobalGetter;
template<>
struct GlobalGetter<int> {
static int GetGlobal(const char *name);
};
template<>
struct GlobalGetter<double> {
static double GetGlobal(const char *name);
};
template<typename T>
T GetGlobal(const char *name)
{
return GlobalGetter<T>::GetGlobal(name);
}
Sugeriría no proporcionar realmente una implementación, solo una simple declaración del método.
La otra opción sería utilizar una aserción en tiempo de compilación. Boost tiene una serie de tales bestias.
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
También está su contraparte de la versión del mensaje, que ayudaría.