especialización de método de plantilla en * nix

Tengo una clase variante que usa alguna especialización de plantilla de funciones para obtener y configurar diferentes tipos que se compilaron y funcionaron bien con Visual Studio 2010. Sin embargo, este código se encuentra en una solución común que también necesita compilarse en redhat, ubuntu, etc.

Recibí un error en la línea de especialización explícita en el ámbito sin espacio de nombres. Pensé que la solución fácil era simplemente definir mis especializaciones fuera de la clase con un calificador de alcance para la clase en el mismo espacio de nombres.

Sin embargo, ahora recibo errores de que la especialización ocurre después de la creación de instancias, ya que otros métodos de la clase para convertir varios tipos están usando esta plantilla dentro de la clase.

Entonces, ¿cuál es la forma correcta de hacer algo como esto:

namespace Example
{
    class CSomeVariant
    {
    public:
        bool toString(std::string& out)
        {
            return get(out);
        }
    private:
        template <typename T>
        bool get(T& val)
        {
            try {
                val = boost::any_cast<T>(m_stored);
            }
            catch (...) {
                return false;
            }
            return true;
        }

        boost::any m_stored;
    };

    template<>
    bool CSomeVariant::get(std::string& val)
    {
        try {
            if (m_stored.type() != typeid(std::string))
               val = convertToString();
            else
               val = boost::any_cast<std::string>(m_stored);
        }
        catch(...) {
            return false;
        }
        return true;
    }
}

Nota: este no es el código real, pero creo que muestra el problema.

preguntado el 03 de mayo de 12 a las 21:05

Raro, parece que debería funcionar... -

¿Por qué estás usando la especialización en lugar de simplemente sobrecargando? -

@ildjarn Um porque... buen punto. Wow, me siento tonto ahora. -

1 Respuestas

El problema es que estás usando el get() función en la definición de clase y luego especializándola después, lo cual no está permitido. De 14.7.3 párrafo 6

Si una plantilla, una plantilla de miembro o el miembro de una plantilla de clase se especializa explícitamente, esa especialización se declarará antes del primer uso de esa especialización que provocaría una instanciación implícita, en cada unidad de traducción en la que se produzca dicho uso. ; no se requiere diagnóstico. Si el programa no proporciona una definición para una especialización explícita y la especialización se usa de una manera que provocaría una creación de instancias implícita o el miembro es una función de miembro virtual, el programa está mal formado, no se requiere diagnóstico.

Una solución es reordenar la definición de clase para que la especialización se declare antes de cualquier uso. En este caso, pude mover el uso en línea de la función hasta después de la especialización.

#include <string>
#include <boost/any.hpp>
namespace Example
{
    class CSomeVariant
    {
    public:
        bool toString(std::string& out);

    private:
       template <typename T>
       bool get(T& val)
       {
           try {
              val = boost::any_cast<T>(m_stored);
           }
           catch (...) {
               return false;
           }
           return true;
       }

       boost::any m_stored;
   };

   template<>
   bool CSomeVariant::get(std::string& val)
   {
       try {
           if (m_stored.type() != typeid(std::string))
              val = convertToString();
           else
              val = boost::any_cast<std::string>(m_stored);
       }
       catch(...) {
           return false;
       }
       return true;
   }


   inline bool CSomeVariant::toString(std::string& out)
   {
        return get(out);
   }
}

contestado el 03 de mayo de 12 a las 21:05

¡Me ganaste por 1 minuto! Acababa de leer sobre esto hoy en mi copia recién llegada de Advanced C++ MetaProgramming. - PlantillaRex

Hay un montón de métodos toThis o toThat, pero esto funcionaría. Seguiré la sugerencia de ildjarn, ya que me gusta eliminar por completo las especializaciones. - AJG85

@ AJG85 Como regla general, trato de evitar funciones especializadas y uso la sobrecarga siempre que puedo. Las reglas son más fáciles de seguir. - Dave S

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.