Я пытаюсь сделать что-то вроде этого:
#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;
}
но я получаю эту ошибку:
error: missing binary operator before token "("
Как правильно сделать условное определение типа?
sizeof
других конструкциях C ++. Он, конечно же, не знает о вещах, которыми вы сами себя создалиtypedef
, поскольку это еще даже не проанализировано.enable_if
илиconditional
для условного определения typedef, но вы не можете использовать для этого препроцессор.sizeof
невозможно работать в условиях препроцессора, заключается в том, что язык определен таким образом, а не в том, как работает реализация.Ответы:
Используйте
std::conditional
мета-функцию из C ++ 11.#include <type_traits> //include this typedef std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64>::type Engine;
Обратите внимание: если тип, который вы используете,
sizeof
является параметром шаблона, скажемT
, вы должны использовать егоtypename
как:typedef typename std::conditional<sizeof(T) <= 4, // T is template parameter std::mt19937, std::mt19937_64>::type Engine;
Или сделать в
Engine
зависимости отT
:template<typename T> using Engine = typename std::conditional<sizeof(T) <= 4, std::mt19937, std::mt19937_64>::type;
Это гибко , потому что теперь вы можете использовать его как:
Engine<int> engine1; Engine<long> engine2; Engine<T> engine3; // where T could be template parameter!
источник
sizeof(int) <= 4
, возможно, не очень переносимый способ, поскольку на 64-битной машине Windows компилятор GCC (MinGW) x64 даетsizeof(int) = sizeof(long) = 4
. Было бы лучшеsizeof(void*) <= 4
.Engine<void*> engine4;
? ;-)std::conditional<sizeof(void*) <= 4, std::mt19937, std::mt19937_64>
в виду в первом фрагменте кода.Engine<void*>
? : Pint
Используя
std::conditional
вы можете сделать это так:using Engine = std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64 >::type;
Если вы хотите сделать
typedef
, вы тоже можете это сделать.typedef std::conditional<sizeof(int) <= 4, std::mt19937, std::mt19937_64 >::type Engine
источник
typename
здесьЕсли у вас нет доступного C ++ 11 (хотя, похоже, у вас есть, если вы планируете использовать
std::mt19937
), вы можете реализовать то же самое без поддержки C ++ 11, используя библиотеку метапрограммирования Boost (MPL) . Вот компилируемый пример:#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; }
Это печатает искаженное имя в
foo
моей системе, так как здесьint
4 байта.источник
if_c
вместо этого? Было бы необходимо проще писать (и понимать):mpl::if_c<sizeof(int)<=4, foo, bar>::type
. Не так ли?mpl::if_c
. Я обновил пример, чтобы использовать этот подход.