Próbuję zrobić coś takiego:
#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;
}
ale otrzymuję ten błąd:
error: missing binary operator before token "("
Jak mogę poprawnie utworzyć warunkową czcionkę?
sizeof
ani o innych konstrukcjach C ++. Z pewnością nie wie o rzeczach, z których sam stworzyłeśtypedef
, ponieważ nie zostało to jeszcze przeanalizowane.enable_if
lub,conditional
aby warunkowo zdefiniować typedef, ale nie możesz użyć do tego preprocesora.sizeof
niemożności działania w warunkach preprocesora jest to, że język jest zdefiniowany w ten sposób, a nie sposób działania implementacji.Odpowiedzi:
Użyj
std::conditional
meta-funkcji z C ++ 11.#include <type_traits> //include this typedef std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64>::type Engine;
Zauważ, że jeśli typ, którego używasz w,
sizeof
jest, powiedzmyT
, parametrem szablonu , musisz użyćtypename
jako:typedef typename std::conditional<sizeof(T) <= 4, // T is template parameter std::mt19937, std::mt19937_64>::type Engine;
Lub
Engine
uzależnij sięT
od:template<typename T> using Engine = typename std::conditional<sizeof(T) <= 4, std::mt19937, std::mt19937_64>::type;
To jest elastyczne , ponieważ teraz możesz go używać jako:
Engine<int> engine1; Engine<long> engine2; Engine<T> engine3; // where T could be template parameter!
źródło
sizeof(int) <= 4
może nie jest zbyt przenośnym sposobem, ponieważ na 64-bitowej maszynie z systemem Windows daje kompilator GCC (MinGW) x64sizeof(int) = sizeof(long) = 4
. Byłby lepszy sposóbsizeof(void*) <= 4
.Engine<void*> engine4;
? ;-)std::conditional<sizeof(void*) <= 4, std::mt19937, std::mt19937_64>
w pierwszym fragmencie kodu.Engine<void*>
? : Pint
:)Używając
std::conditional
możesz to zrobić tak:using Engine = std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64 >::type;
Jeśli chcesz zrobić
typedef
, możesz to zrobić.typedef std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64 >::type Engine
źródło
typename
tutajJeśli nie masz dostępnego C ++ 11 (chociaż wydaje się, że tak, jeśli planujesz używać
std::mt19937
), możesz zaimplementować to samo bez obsługi C ++ 11 za pomocą biblioteki Boost Metaprogramming Library (MPL) . Oto przykład do kompilacji:#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; }
Spowoduje to wyświetlenie zniekształconej nazwy
foo
w moim systemie, ponieważint
tutaj jest 4 bajty.źródło
if_c
zamiast tego? Byłoby koniecznością łatwiej napisać (i zrozumieć)mpl::if_c<sizeof(int)<=4, foo, bar>::type
. Prawda?mpl::if_c
. Zaktualizowałem przykład, aby zamiast tego użyć tego podejścia.