Как сделать условный typedef в С++

Я пытаюсь сделать что-то вроде этого:

#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 "("

Как я могу правильно сделать условный typedef?

Ответ 1

Используйте мета-функцию std::conditional из С++ 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!

Ответ 2

Используя 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

Ответ 3

Если у вас нет доступного С++ 11 (хотя он появляется, если вы планируете использовать std::mt19937), тогда вы можете реализовать одно и то же без поддержки С++ 11, используя Увеличить библиотеку метапрограммирования (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 байта.