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?
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 T
entonces 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 dasizeof(int) = sizeof(long) = 4
. Una mejor manera seríasizeof(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
Rapptz
Usando std::conditional
puedes hacerlo así:
using Engine = std::conditional<sizeof(int) <= 4,
std::mt19937,
std::mt19937_64
>::type;
Si quieres hacer un typedef
Tu 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
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
El preprocesador no sabe nada sobre
sizeof
u otras construcciones de C++. Eso seguramente no sabe acerca de las cosas que tú mismo creaste contypedef
ya 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
oconditional
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