tipos template plantillas funciones curso con clase ats c++ templates

c++ - plantillas - templates en c



Pasar un literal de cadena como parĂ¡metro a una clase de plantilla de C++ (10)

Quiero una clase que tome dos parámetros en su constructor. El primero puede ser int, double o float, entonces, y el segundo es siempre un literal de cadena "my string"

template<typename T> class demo { T data; std::string s; public: demo(T d,std::string x="my string"):data(d),s(x) //Your constructor { } };

No estoy seguro, pero ¿es esto algo lo que quieres?

Quiero una clase que tome dos parámetros en su constructor. El primero puede ser int, double o float, por lo que <typename T> , y el segundo es siempre un literal de cadena "my string", así que supongo que const char * const .

¿Alguien puede darme algún código compilable que declare una plantilla de clase simple como se describe y declare un objeto de esa clase?

Gracias


una cadena literal "mi cuerda", así que supongo que const char * const

En realidad, los literales de cadena con n caracteres visibles son del tipo const char[n+1] .

#include <iostream> #include <typeinfo> template<class T> void test(const T& t) { std::cout << typeid(t).name() << std::endl; } int main() { test("hello world"); // prints A12_c on my compiler }


EDIT: ok, el título de tu pregunta parece ser engañoso

"Quiero una clase que tenga dos parámetros en su constructor. La primera puede ser int, double o float, entonces, y la segunda es siempre una cadena literal" my string ", así que supongo que const char * const."

Parece que estás tratando de lograr:

template<typename T> class Foo { public: Foo(T t, const char* s) : first(t), second(s) { // do something } private: T first; const char* second; };

Esto funcionaría para cualquier tipo, para el primer parámetro: int , float , double , whatever.

Ahora, si realmente quiere restringir el tipo del primer parámetro para que sea solo int , float o double ; puedes encontrar algo más elaborado como

template<typename T> struct RestrictType; template<> struct RestrictType<int> { typedef int Type; }; template<> struct RestrictType<float> { typedef float Type; }; template<> struct RestrictType<double> { typedef double Type; }; template<typename T> class Foo { typedef typename RestrictType<T>::Type FirstType; public: Foo(FirstType t, const char* s) : first(t), second(s) { // do something } private: FirstType first; const char* second; }; int main() { Foo<int> f1(0, "can"); Foo<float> f2(1, "i"); Foo<double> f3(1, "have"); //Foo<char> f4(0, "a pony?"); }

Si elimina el comentario en la última línea, obtendrá efectivamente un error de compilación.

Los literales de cadena no son permitidos por C ++ 2003

ISO / IEC 14882-2003 §14.1:

14.1 Parámetros de la plantilla

Un parámetro de plantilla sin tipo debe tener uno de los siguientes tipos (opcionalmente calificado):

- tipo integral o de enumeración,

- puntero a objeto o puntero a función,

- referencia al objeto o referencia a la función,

- puntero a miembro.

ISO / IEC 14882-2003 §14.3.2:

14.3.2 Argumentos de plantilla sin tipo

Un argumento de plantilla para un parámetro de plantilla que no sea de tipo y sin plantilla será uno de:

- una expresión constante constante de tipo integral o de enumeración; o

- el nombre de un parámetro de plantilla sin tipo; o

- la dirección de un objeto o función con vinculación externa, incluidas plantillas de función e ID de plantilla de función, pero excluyendo miembros de clase no estáticos, expresada como expresión & id donde & es opcional si el nombre hace referencia a una función o matriz, o si el parámetro de plantilla correspondiente es una referencia; o

- un puntero al miembro expresado como se describe en 5.3.1.

[Nota: Un literal de cadena (2.13.4) no satisface los requisitos de ninguna de estas categorías y, por lo tanto, no es un argumento de plantilla aceptable.

[Ejemplo:

template<class T, char* p> class X { //... X(); X(const char* q) { /* ... */ } }; X<int,"Studebaker"> x1; //error: string literal as template-argument char p[] = "Vivisectionist"; X<int,p> x2; //OK

-end example] -finalizar nota]

Y parece que no va a cambiar en el C ++ 0X venidero, consulte el borrador actual 14.4.2 . Argumentos sin tipo de plantilla .


En base a sus comentarios bajo la respuesta de Niel, otra posibilidad es la siguiente:

#include <iostream> static const char* eventNames[] = { "event_A", "event_B" }; enum EventId { event_A = 0, event_B }; template <int EventId> class Event { public: Event() { name_ = eventNames[EventId]; } void print() { std::cout << name_ << std::endl; } private: const char* name_; }; int main() { Event<event_A>().print(); Event<event_B>().print(); }

huellas dactilares

event_A event_B


Esta es una solución con MPLLIBS para pasar cadenas como argumentos de plantilla (C ++ 11).

#include <iostream> #include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs #include <boost/mpl/string.hpp> // -std=c++11 template<class a_mpl_string> struct A { static const char* string; }; template<class a_mpl_string> const char* A< a_mpl_string > ::string { boost::mpl::c_str< a_mpl_string >::value }; // boost compatible typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type; int main ( int argc, char **argv ) { std::cout << a_string_type{}.string << std::endl; return 0; }

huellas dactilares:

any string as template argument

La lib en github: https://github.com/sabel83/mpllibs


Lo sentimos, C ++ actualmente no admite el uso de literales de cadena (o literales reales) como parámetros de plantilla.

Pero volver a leer su pregunta, ¿es eso lo que está preguntando? No puedes decir:

foo <"bar"> x;

pero puedes decir

template <typename T> struct foo { foo( T t ) {} }; foo <const char *> f( "bar" );


Más allá de la respuesta de Neil: una forma de usar cadenas con plantillas como lo desea es definir una clase de rasgos y definir la cadena como un rasgo del tipo.

#include <iostream> template <class T> struct MyTypeTraits { static const char* name; }; template <class T> const char* MyTypeTraits<T>::name = "Hello"; template <> struct MyTypeTraits<int> { static const char* name; }; const char* MyTypeTraits<int>::name = "Hello int"; template <class T> class MyTemplateClass { public: void print() { std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl; } }; int main() { MyTemplateClass<int>().print(); MyTemplateClass<char>().print(); }

huellas dactilares

My name is: Hello int My name is: Hello


No puede pasar un literal de cadena directamente como un parámetro de plantilla.

Pero puedes acercarte:

template<class MyString = typestring_is("Hello!")> void MyPrint() { puts( MyString::data() ); } ... // or: MyPrint<typestring_is("another text")>(); ...

Todo lo que necesita es un pequeño archivo de encabezado desde here .

Alternativas:

  • Defina una char const * global de char const * y páselo a la plantilla como puntero. ( here )

    Drawback: requiere código adicional fuera de la lista de argumentos de la plantilla. No es adecuado si necesita especificar el literal de cadena "en línea".

  • Use una extensión de idioma no estándar. ( here )

    Drawback: no se garantiza que funcione con todos los compiladores.

  • Use BOOST_METAPARSE_STRING . ( here )

    Drawback: su código dependerá de la biblioteca de Boost.

  • Utilice un paquete de parámetros de plantilla variadica de char, por ejemplo, str_t<''T'',''e'',''s'',''t''> .

    Esto es lo que la solución anterior hace por ti detrás de escena.


Puede tener un parámetro de plantilla const char* non-type y pasarle una variable const char[] con enlace static , que no está tan lejos de pasar un literal de cadena directamente.

#include <iostream> template<const char *str> struct cts { void p() {std::cout << str;} }; static const char teststr[] = "Hello world!"; int main() { cts<teststr> o; o.p(); }

http://coliru.stacked-crooked.com/a/64cd254136dd0272


inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; } template <const wchar_t *GetLiteralFunc(void)> class MyType { void test() { std::cout << GetLiteralFunc; } } int main() { MyType<GetTheStringYouWant>.test(); }

Pruébelo pegando la dirección de una función como argumento de la plantilla.