Quiero una clase que toma dos parámetros en su constructor. La primera puede ser un int, double o float, así <typename T>, y el segundo es siempre un literal de cadena «mi cadena», así que supongo que const char * const.

Puede alguien darme algún código compilable en la que se declara una simple plantilla de clase como se describe y se declara un objeto de esa clase?

Gracias

  • Si te refieres a los parámetros de la plantilla, consulta de Neil respuesta a continuación; pero si te refieres a cto r de parámetros (como parece que usted escribió?) a continuación, usted ni siquiera necesita una plantilla. Por favor aclarar.
  • El literal de cadena "my string" es de tipo const char[10]
InformationsquelleAutor Mawg | 2010-01-09

12 Comentarios

  1. 22

    Lo siento, C++ no es compatible actualmente con el uso de literales de cadena (real o literales) como parámetros de la plantilla.

    Pero la re-lectura de tu pregunta, es que lo que están pidiendo? Usted no puede decir:

    foo <"bar"> x;

    pero se puede decir

    template <typename T>
    struct foo {
       foo( T t ) {}
    };
    
    foo <const char *> f( "bar" );
    • Do C++0x variadic plantillas de apoyo integral argumentos? Usted probablemente podría hacer algo desagradable con representación de cadenas como la lista de chars.
    • tal vez usted podría rompiera con 4 char largo de literales (apoyado por todos los compiladores?) y variadic plantillas — sería una buena respuesta en LO mismo, pero se vería feo en el código de producción 🙂
    • Neil, que se ve muy buena, pero desde que soy tonto, se puede corregir este código? Traté de adaptar el suyo para tomar dos parámetros, la cual debe ser lo suficientemente simple … <pre> plantilla<typename E, typename S> Evento de clase { public: Evento(E eventId, S eventName); // constructor privado: E _eventId; char _eventName[MAX_EVENT_NAME_LENGTH + 1]; }; < pre> y tratar de crear una instancia con <pre> enum enum1 {eventA, eventB}; Eventos<enum1, const char *> testEventA(eventA, «A»); < pre> pero me da errores de compilador – véase el siguiente comentario, quedando sin espacio
    • sht!! Cómo dar formato a los comentarios, si PREVIAMENTE no funciona? – tratando de crear una instancia de » plantilla<clase E, clase S> clase – expresión de inicializador de la lista de tratados como expresión compuesta – no válido conversión de ‘const char‘ a ‘int’ test_fsm.cpp – tipo no válido en la declaración ante ‘(‘ token test_fsm.cpp – argumento de plantilla para la ‘plantilla<clase E, clase S> Evento de clase’ se usa de tipo local ‘testFsmClasses::TesEventConstructor()::enum1’
    • Editar tu pregunta original. Y nunca intente utilizar HTML para dar formato a la pregunta o las respuestas. Utilice los botones de poco por encima del editor.
    • Hola, Neil, Idealmente, yo hubiera preferido un ejemplo con dos parámetros, uno es un valor de enumeración y la otra una cadena, siendo el nombre del evento. Hackeando el código, voy a trabajar, pero necesarios para el uso de un #define como puedo hacer que funcione de otra manera – porque no se puede pasar de un literal de cadena como un parámetro de plantilla. Esto es lo que cam con: (siguiente comentario, no hay suficiente espacio aquí)
    • plantilla de <typename EventId, typename EventName> Evento de clase { public: Evento(EventId ventId, nombre del evento nombre del evento ) {} }; enum evento{eventA, eventB}; #define DECLARE_EVENT(w, x, y, z) de Eventos<x, const char *> w(y, z ) int main(int argc, char *argv[]) { DECLARE_EVENT(e1, evento, evento,»event_A»); DECLARE_EVENT(e2, evento, eventA,»event_B»); return 0; }
    • hmm, yo a pesar de que cuatro espacios en el inicio de cada línea sería un pre-formateado bloque de código (????)
    • Neil, siento ser tan tonto – pero los botones – están ahí para comentarios? Yo sí veo a ellos en busca de respuestas. y, a partir de lo que he leído – de los botones – cuatro espacios debe PRE – CÓDIGO siento ser tan tonto…
    • Acabo de hacer exactamente eso para ver si se podía hacer: stackoverflow.com/questions/1826464/…
    • Nota importante: puede tiene un const char* no-tipo de parámetro de plantilla, que no es todo lo que lejos de pasar de un literal de cadena. coliru.stacked-crooked.com/a/64cd254136dd0272

  2. 37

    Más de Neil respuesta: una forma de utilizar las cadenas con las plantillas que quiero 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();
    }

    imprime

    My name is: Hello int
    My name is: Hello
    • Esto se ve muy interesante. Puede ser el masaje para pasar la cadena como parámetro y espectáculo y ejemplo de declaración de un objeto?
    • Como por ejemplo, en virtud de su Niel de la respuesta (en realidad, usted debe actualizar su pregunta, diciendo: «Actualización: Esto es lo que quiero»), se quiere diferenciar entre las clases base (solamente) en una cadena de parámetro de plantilla. Esto es imposible (véase el Niel de la respuesta). Pero si se quiere diferenciar entre clases basadas en EventId, entonces usted puede utilizar el nombre del evento como un campo en el rasgo de clase como por mi respuesta.
    • También ver a mi otro recién agregado respuesta.
    • Gracias, eso es justo lo que necesitaba 😉
    • Esto es justo lo que necesitaba. Me desconecté un poco con una macro de preprocesador que toma tres parámetros: Un nombre de tipo, una cadena literal, y la plantilla de clase de parámetro(s). La macro a continuación se define la plantilla de especialización para el parámetro de plantilla(s), establece el rasgo de la cadena literal, y, finalmente, las definiciones de tipos de la plantilla de clase con los parámetros de la plantilla como el nombre del tipo. Así que mediante este mecanismo se reduce a una simple llamada de macro de preprocesador en lugar de una docena de líneas de C++ de código de la plantilla.
  3. 16

    Que puede tener un const char* no-tipo de parámetro de plantilla, y pasar una const char[] variable con static de vinculación, que no es todo lo que lejos de pasar de 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

    • Este debe ser fijado respuesta. Quisiera no te pierdas esta antes de saber por mí mismo… un mes más tarde de lo que necesita.
  4. 11

    Esta es una solución con MPLLIBS a pasar una de las 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;
    }

    imprime:

    any string as template argument

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

  5. 11
    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();
    }

    Tratar con pasing la dirección de una función como argumento de plantilla.

  6. 6

    La base de sus comentarios bajo Niel de la respuesta, 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();
    }

    imprime

    event_A
    event_B
    • Sí, funciona, y es que vale la pena considerar. Lo que me preocupa, sin embargo, es que es posible cometer un error y salir de la alineación. Sería «mejor» para pasar tanto el valor de enumeración y de la cadena como un par (pero, por supuesto, usted todavía puede cometer errores no demasiado)
    • Yo uso los valores de enumeración con el # operador para generar las representaciones de cadena.
    • Este es el más limpio respuesta, pero si se utiliza en el encabezado de los archivos que va a causar problemas durante la vinculación , es decir, duplicar definiciones, etc. La aceptación de respuesta utiliza plantillas en una estructura para ayudar a que el enlazador de casarse con las definiciones en tiempo de compilación.
    • Tenga en cuenta que esto no funcionará si dos enum entradas comparten el mismo valor subyacente. Coincidirían en el eventNames[] de búsqueda.
  7. 4

    EDICIÓN: aceptar el título de tu pregunta, parece ser engañosa

    «Quiero una clase que toma dos parámetros en su constructor. La primera puede ser un int, double o float, así , y el segundo es siempre un literal de cadena «mi cadena», así que supongo que const char * const.»

    Parece que estamos 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 funciona para cualquier tipo, para el primer parámetro: int, float, double, lo que sea.

    Ahora bien, si usted realmente desea restringir el tipo de el primer parámetro a sólo int, float o double; usted puede venir para arriba con 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 usted quite el comentario de la última línea, usted va a obtener efectivamente un error del compilador.


    Literales de cadena no son permitidos por C++2003

    ISO/IEC 14882-2003 §14.1:

    14.1 parámetros de la Plantilla

    Un no-tipo de plantilla-parámetro tendrá uno de los siguientes (optionallycv-calificado) tipos:

    integral o tipo de enumeración,

    — puntero a objeto o un 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 Plantilla de no-tipo de argumentos

    Una plantilla con el argumento de que un no-tipo, sin plantilla plantilla parámetro será uno de:

    integrante expresión constante de la integral o tipo de enumeración; o

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

    — la dirección de un objeto o función con la vinculación externa, incluyendo la función de las plantillas y la función de la plantilla de id, pero excluyendo a los no-estática de los miembros de la clase, expresada como & id de expresión donde el & es opcional si el nombre se refiere a una función o matriz, o si la plantilla correspondiente parámetro es una referencia; o

    — un puntero a miembro expresa como se describe en 5.3.1.

    [Nota:Un literal de cadena (2.13.4) no satisfacer los requisitos de una de estas categorías y por lo tanto no es aceptable plantilla-argumento.

    [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 ejemplo] —fin de la nota]

    Y parece que no va a cambiar en las próximas C++0X, ver el actual proyecto de 14.4.2 Plantilla de no-tipo de argumentos.

    • Gregorio, he leído la explicación similar en otros lugares, pero no está tan claro. El código tiene como yo lo entiendo, y se debe trabajar -, pero da error en Linux con G++ (de hecho, tengo errores de compilación con dos buenas buscando sugerencias anteriores – ¿de verdad puedo ser tan tonto?)
    • ver editado mi respuesta
    • He copiado el código y aún así no funciona. Comeau C/C++ 4.3.10.1 (Octubre 6 de 2008, 11:28:09) para ONLINE_EVALUATION_BETA2 de derechos de Autor 1988-2008 Comeau de Computación. Todos los derechos reservados. MODO:la estricta errores de C++ C++0x_extensions «ComeauTest.c», de la línea 14: error: error de expresión debe tener un valor constante X<int a,p> x2; //OK
  8. 4

    Que no se puede pasar de un literal de cadena directamente como un parámetro de plantilla.

    Pero usted puede conseguir cerca de:

    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 de aquí.


    Alternativas:

    • Definir un mundial char const * y se pasa a la plantilla como puntero. (aquí)

      Inconveniente: Requiere código adicional fuera de la plantilla de lista de argumentos. No es el adecuado, si es necesario especificar el literal de cadena «en línea».

    • Usar un lenguaje estándar de extensión. (aquí)

      Inconveniente: No se garantiza que funcione con todos los compiladores.

    • Uso BOOST_METAPARSE_STRING. (aquí)

      Inconveniente: Su código dependerá del Impulso de la biblioteca.

    • Utilizar un variadic parámetro de plantilla pack de char, por ejemplo,str_t<'T','e','s','t'>.

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

  9. 3

    Quiero una clase que toma dos parámetros en su constructor. La primera puede ser un int, double o float, así , y el segundo es siempre un literal de cadena «mi cadena»

    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 este algo es lo que quieres?

    • Puede y quiere hacer parte de ese público de clase, o simplemente utilizar struct en los ejemplos, lo que reduce en gran medida el desorden. 🙂
    • Gracias, corregido 🙂
    • Que está mirando muy de cerca! Pero, ¿cómo puedo pasar un diferente «mi cadena» como parámetro del constructor cada vez que me instanciar?
    • no necesita paso «mi cadena». Sólo trate de: demo<int> d(1); // el segundo parámetro es «mi cadena» por defecto demo<doble> d1(1.4); // el segundo parámetro es de nuevo «mi cadena» por defecto
    • Leer acerca de argumento por defecto constructores aquí: people.cs.vt.edu/~kafura/cs2704/default.html
  10. 2

    un literal de cadena «mi cadena», así que supongo que const char * const

    De hecho, los literales de cadena con n caracteres visibles son de 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
    }
    • Este pasa a la tipo de la literal de cadena como parámetro de plantilla, no el literal de cadena en sí.
  11. 0

    Estaba struggeling con un problema similar y, finalmente, llegó con una concisa aplicación que desempaqueta el literal de cadena en un char… parámetro de plantilla pack y sin el uso de gnu literal operador extensión de plantilla de

    #include <utility>
    
    template <char ... Chars>
    struct type_string_t {
        static constexpr const char data[sizeof... (Chars)] = {Chars...};
    };
    
    template <char s(std::size_t), std::size_t... I>
    auto type_string_impl(std::index_sequence<I...>) {return type_string_t<s(I)...>();};
    
    #define type_string(s) decltype (type_string_impl<[](std::size_t i) {return s[i];}> \
    (std::make_index_sequence<sizeof (s)>()))
    
    static_assert (std::is_same<type_string("String_A"),
                                type_string("String_A")>::value);
    static_assert (!std::is_same<type_string("String_A"),
                                 type_string("String_B")>::value);
    • lo que compilador usas ? falla al compilar con MSVC c++17
    • De acuerdo. Qué compilador está utilizando. No funciona en c++17 compilador que he visto. Esto es porque usted no puede declarar una lambda en un parámetro de plantilla.
  12. 0

    Quizás no en lo que el OP está pidiendo, pero si uso boost, puede crear una macro como este por ejemplo:

    #define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value

    A continuación, utilizar la siguiente manera:

    template<const char* str>
    structe testit{
    };
    testit<C_STR("hello")> ti;

Dejar respuesta

Please enter your comment!
Please enter your name here