Cómo hacer un typedef condicional en C++

5 minutos de lectura

avatar de usuario
Martín Drozdik

Estoy tratando de hacer algo como esto:

#include <iostream>
#include <random>

typedef int Integer;

#if sizeof(Integer) <= 4
    typedef std::mt19937     Engine;
#else
    typedef std::mt19937_64  Engine;
#endif

int main()
{
    std::cout << sizeof(Integer) << std::endl;
    return 0;
}

pero me sale este error:

error: missing binary operator before token "("

¿Cómo puedo hacer correctamente el typedef condicional?

  • El preprocesador no sabe nada sobre sizeofu otras construcciones de C++. Eso seguramente no sabe acerca de las cosas que tú mismo creaste con typedefya que aún no se ha analizado.

    – Carreras de ligereza en órbita

    25 de julio de 2013 a las 9:44


  • podrías usar enable_if o conditional para definir condicionalmente typedefs, pero no puede usar el preprocesador para eso.

    –Bartek Banachewicz

    25 de julio de 2013 a las 9:44


  • @LightnessRacesinOrbit: el preprocesamiento y la compilación están integrados en GCC, por lo que no solo no es seguro que el código de procesamiento del software no conozca las definiciones de tipo creadas por el usuario, sino que se sabe que es falso en el caso de GCC. La razón sizeof no puede funcionar en condiciones de preprocesador es porque el lenguaje está definido de esa manera, no por cómo funciona una implementación.

    –Eric Postpischil

    28 de agosto de 2013 a las 15:16

  • @LightnessRacesinOrbit: las fases de traducción definen la sintaxis y la semántica, no el orden de procesamiento. Según C++ 2011 (N3092) 2.2 [lex.phases] nota 11, “Las implementaciones deben comportarse como si estas fases separadas ocurrieran, aunque en la práctica las diferentes fases pueden juntarse”. Mi punto sobre GCC es relevante porque demuestra que su afirmación de que así es como funciona una implementación es incorrecta. En otras palabras, su comentario reclamación (es que un método particular de implementación previene esto. Pero no es la implementación lo que impide esto (nosotros pudo hazlo); es la definición del lenguaje.

    –Eric Postpischil

    28 de agosto de 2013 a las 15:35

  • @Eric: No quise reclamar nada sobre implementaciones en absoluto. Ciertamente no mencioné ninguno en particular. Mi comentario indicó un comportamiento que está sujeto a la regla como si, al igual que el suyo. No creo que en realidad estemos en desacuerdo en nada aquí: su lenguaje como abogado bien podría haber venido directamente del espejo. 🙂

    – Carreras de ligereza en órbita

    28 de agosto de 2013 a las 17:09


avatar de usuario
Nawaz

Utilizar el std::conditional metafunción de C++11.

#include <type_traits>  //include this

typedef std::conditional<sizeof(int) <= 4,
                         std::mt19937,
                         std::mt19937_64>::type Engine;

Tenga en cuenta que si el tipo que utiliza en sizeof es un parámetro de plantilla, digamos Tentonces tienes que usar typename como:

typedef typename std::conditional<sizeof(T) <= 4, // T is template parameter
                                  std::mt19937,
                                  std::mt19937_64>::type Engine;

o hacer Engine depender de T como:

template<typename T>
using Engine = typename std::conditional<sizeof(T) <= 4, 
                                         std::mt19937,
                                         std::mt19937_64>::type;

Eso es flexibleporque ahora puedes usarlo como:

Engine<int>  engine1;
Engine<long> engine2;
Engine<T>    engine3; // where T could be template parameter!

  • +1 Nitpick menor: Comprobación de sizeof(int) <= 4 quizás no sea una forma muy portátil ya que en una máquina Windows de 64 bits, el compilador GCC (MinGW) x64 da sizeof(int) = sizeof(long) = 4. Una mejor manera sería sizeof(void*) <= 4.

    – leyendas2k

    25 de julio de 2013 a las 13:12


  • @legends2k: quieres decir Engine<void*> engine4;? 😉

    – Nawaz

    25 de julio de 2013 a las 13:32

  • @Nawaz: Por supuesto que no 🙂 Quise decir std::conditional<sizeof(void*) <= 4, std::mt19937, std::mt19937_64> en el primer fragmento de código.

    – leyendas2k

    25 de julio de 2013 a las 13:50


  • @legends2k: ¿Por qué usarías eso si te he proporcionado Engine<void*>? :PAGS

    – Nawaz

    25 de julio de 2013 a las 13:59

  • @Nawaz: Jaja… eso es verdad. Sin embargo, pensé que el OP probablemente debería conocer el peligro de detectar la arquitectura en función del tamaño de un int 🙂

    – leyendas2k

    25 de julio de 2013 a las 15:32


avatar de usuario
Rapptz

Usando std::conditional puedes hacerlo así:

using Engine = std::conditional<sizeof(int) <= 4, 
                               std::mt19937, 
                               std::mt19937_64
                               >::type;

Si quieres hacer un typedefTu también puedes hacer eso.

typedef std::conditional<sizeof(int) <= 4, 
                         std::mt19937, 
                         std::mt19937_64
                         >::type Engine

  • No hay necesidad de typename aquí

    – gx_

    25 de julio de 2013 a las 9:46

  • @gx_ Sí, solía ponerlo allí por trabajar con plantillas, no con tipos concretos.

    – Rapptz

    25 de julio de 2013 a las 9:47

  • @LightnessRacesinOrbit Bueno, lo arreglé un poco.

    – Rapptz

    25 de julio de 2013 a las 10:23

avatar de usuario
jason r

Si no tiene C++ 11 disponible (aunque parece que lo tiene si planea usar std::mt19937), entonces puede implementar lo mismo sin compatibilidad con C++ 11 usando el Biblioteca de metaprogramación Boost (MPL). Aquí hay un ejemplo compilable:

#include <boost/mpl/if.hpp>
#include <iostream>
#include <typeinfo>

namespace mpl = boost::mpl;

struct foo { };
struct bar { };

int main()
{
    typedef mpl::if_c<sizeof(int) <= 4, foo, bar>::type Engine;

    Engine a;
    std::cout << typeid(a).name() << std::endl;
}

Esto imprime el nombre destrozado de foo en mi sistema, como un int es de 4 bytes aquí.

  • ¿Por qué no usas if_c ¿en cambio? Sería más fácil de escribir (y entender): mpl::if_c<sizeof(int)<=4, foo, bar>::type. ¿no es así?

    – Nawaz

    25 de julio de 2013 a las 17:12


  • @Nawaz: De hecho, eso es mejor de varias maneras. me habia olvidado mpl::if_c. Actualicé el ejemplo para usar ese enfoque en su lugar.

    – Jason R.

    25 de julio de 2013 a las 17:52

¿Ha sido útil esta solución?