Pregunta

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 " default " función. Es decir, quiero hacer todas las llamadas a GetGlobal & Lt; t & Gt; donde 't' no es un error int o doble.

Por ejemplo, GetGlobal < char > () debería ser un error de tiempo de compilación.

Traté de eliminar la función predeterminada, pero, como imaginé, recibí muchos errores. Entonces, ¿hay alguna forma de & "; deshabilitar &"; y permitir llamadas solo a las versiones especializadas de la función?

¡Gracias!

¿Fue útil?

Solución

Para obtener un error en tiempo de compilación, impleméntelo como:

template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined

Si usa Boost, podría hacerlo más elegante:

template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }

C ++ Standard garantiza que no existe tal tipo que tenga un tamaño 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 demás.

Otros consejos

Aunque es una pregunta antigua y desactualizada, vale la pena señalar que C++11 había resuelto este problema utilizando funciones eliminadas:

template<typename T>
T GetGlobal(const char *name) = delete;

template<>
int GetGlobal<int>(const char *name);

UPDATE

Esto no se compilará en MacOS llvm 8. Se debe a un defecto que todavía tiene 4 años de antigüedad (consulte este informe de error ).

La siguiente solución se ajustará al problema (usando 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);

UPDATE

Visual studio 15.9 tiene el mismo error. Use la solución anterior para ello.

Si no lo implementa, al menos obtendrá un error de vinculador. Si desea un error en tiempo de compilación, puede hacerlo con 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 usar una afirmación en tiempo de compilación. Boost tiene varias de esas bestias.

namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
                            boost::same_type<T, int> >));

También existe su versión de mensaje equivalente, lo que ayudaría.

Las siguientes son técnicas alternativas al uso de boost:

Declarar 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;
}

Use 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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top