Pregunta

Necesito una plantilla como esta, que funcione perfectamente

template <typename container> void mySuperTempalte (const container myCont)
{
    //do something here
}

luego quiero especializar la plantilla anterior para std :: string, así que se me ocurrió

template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
    //check type of container
    //do something here
}

que no funciona, y arroja un error. Me gustaría hacer que el segundo ejemplo funcione y luego, si es posible, me gustaría agregar algo de código en la plantilla para verificar si se usó un std :: vector / std :: deque / std :: list, para hacer algo diferente en cada uno caso. Así que utilicé plantillas porque el 99% del código es el mismo tanto para vectores como para deques, etc.

¿Fue útil?

Solución

Si entiendo su problema correctamente, tiene un algoritmo que funcionará para el vector de contenedores STL, deque, etc., pero está intentando escribir una especialización de plantilla para la cadena. Si este es el caso, puede escribir el método de plantilla generalizado que definió en su pregunta: -

template<typename container> void mySuperTempalte( const container &myCont )
{
    // Implement STL container code
}

Luego, para su especialización de cadenas declara: -

template<> void mySuperTempalte( const container<std::string> &myCont )
{
    // Implement the string code
}

Para cualquier otra especialización, simplemente cambie la declaración de tipo para myCont. Si realmente necesita hacer esto para los contenedores vector y deque, haga que el parámetro de la plantilla sea el parámetro para el tipo en ese contenedor en lugar del contenedor en sí, como se sugiere en Sep.

template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
    // check type of container
    // do something here
}

Vale la pena intentar evitar esto haciendo que su primera implementación funcione con todos los contenedores STL para hacer su vida más fácil, entonces solo necesita la especialización para la clase de cadena. Incluso considere la posibilidad de convertir su cadena en un vector para evitar la especialización en conjunto.

En una nota al margen, he cambiado el parámetro contenedor a una referencia constante, asumo que esto es lo que quieres, ya que de todos modos declaras la constante objeto, de esta forma evitas una copia.

Otros consejos

Especializarse:

template<> void mySuperTempalte<std:string>(const std::string myCont)
{
    //check type of container
    //do something here
}

Especializarse en vectores:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

Especializarse en deque:

template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
    //check type of container
    //do something here
}

¿Has probado un parámetro de nombre de tipo de plantilla? La sintaxis es un poco rara porque emula la sintaxis utilizada para declarar dicho contenedor. Hay un buen artículo InformIT que explica esto con más detalle.

template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}

¡Tenga en cuenta que también debe declarar el argumento como referencia!

Por cierto: este comentario

//check type of container

es un claro regalo de que estás haciendo algo mal. Usted no desea verificar el tipo de contenedor. En su lugar, la sobrecarga de usuarios es más sofisticada, como se muestra en la respuesta de septiembre.

Las respuestas hasta ahora parecen ser útiles, pero creo que usaría una construcción diferente. Espero que todos los contenedores definan value_type, al igual que los contenedores STL. Por lo tanto, puedo escribir

inline template <typename C> void mySuperTemplate (C const& myCont)
{
    mySuperTemplateImpl<C, typename C::value_type>(myCont);
}

En general, es más fácil actuar sobre un parámetro que hayas extraído explícitamente.

@sep

Solución 'simple'

La respuesta publicada por 'sep' es bastante buena, probablemente lo suficientemente buena para el 99% de los desarrolladores de aplicaciones, pero podría mejorar algo si es parte de una interfaz de biblioteca, para repetir:

  

Especializarse en vectores:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

Esto funcionará siempre que la persona que llama no esté usando std :: vector. Si esto funciona lo suficientemente bien para usted, para especializarse en vectores, listas, etc., deténgase aquí y simplemente use eso.

Solución más completa

Primero, tenga en cuenta que no puede especializar parcialmente las plantillas de funciones, puede crear sobrecargas. Y si dos o más de ellos coinciden en la misma medida, obtendrás " sobrecarga ambigua " errores Por lo tanto, debemos hacer exactamente una coincidencia en cada caso que desee apoyar.

Una técnica para hacer esto es usar la técnica enable_if - enable_if le permite eliminar selectivamente las sobrecargas de la plantilla de función de la posible lista de coincidencia utilizando una regla de lenguaje poco clara ... básicamente, si alguna expresión booleana es falsa, la sobrecarga se convierte en 'invisible'. Busque SFINAE para más información si tiene curiosidad.

Ejemplo. Este código se puede compilar desde la línea de comandos con MinGW (g ++ parametersize.cpp) o VC9 (cl / EHsc parametersize.cpp) sin error:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };

template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };

namespace detail{
    // our special function, not for strings
    //   use ... to make it the least-prefered overload
    template <class Container>
    void SpecialFunction_(const Container& c, ...){
        cout << "invoked SpecialFunction() default\n";
    }

    // our special function, first overload:
    template <class Container>
    // enable only if it is a container of mutable strings
    typename enable_if<
        is_same<typename Container::value_type, string>::value, 
        void
    >::type
    SpecialFunction_(const Container& c, void*){
        cout << "invoked SpecialFunction() for strings\n";
    }
}

// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
    detail::SpecialFunction_(c, 0);
}

int main(){
    vector<int> vi;
    cout << "calling with vector<int>\n";
    SpecialFunction(vi);

    vector<string> vs;
    cout << "\ncalling with vector<string>\n";
    SpecialFunction(vs);
}

Salida:

d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default

calling with vector<string> invoked
SpecialFunction() for strings

d:\scratch>

Si se trata de un buen diseño o no, se deja para más discusión. De todos modos, puede detectar el tipo de contenedor utilizando especializaciones de plantillas parciales. En particular:

enum container_types
{
   unknown,
   list_container,
   vector_container
};

template <typename T>
struct detect_container_
{
   enum { type = unknown };
};

template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
   enum { type = vector_container };
};

template <typename V>
struct detect_container_< std::list<V> >
{
   enum { type = list_container };
};

// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
   return static_cast<container_types>( detect_container_<T>::type );
}

int main()
{
   std::vector<int> v;

   assert( detect_container( v ) == vector_container );
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top