Постоянные выражения, чтобы обнаруживать присутствие и стоимость макросов

Я делаю большие усилия, чтобы переводить макросы моих проектов в постоянные выражения, которые могли бы быть использованными с if constexpr. На данный момент я достиг почти удовлетворительных результатов делая какие-то приемы с макросами, начинаю тем, что определяю макросы, чтобы преобразовывать стоимость в текст:

#define STRINGIFY(X) #X
#define TO_STRING(X) STRINGIFY(X)

Эти макросы ведут себя удивительным способом, переместив существующие или несуществующие определения, например следующий код:

std::cout << TO_STRING(_DEBUG) << '\n';

Образец _DEBUG если макрос homónima не определен, в то время как, если определен образец стоимость макроса. Тип вытекающей стоимости будет всегда буквальным текста (ввиду оператора # макроса STRINGIFY). Я использую этот прием, чтобы создавать перечисленного следующего:

template <int SIZE>
constexpr bool b(const char (&definition)[SIZE])
{
    return definition[0] != '_';
}

enum operating_system : bool
{
    iOS     = b(TO_STRING(__APPLE__)),
    Windows = b(TO_STRING(__MINGW32__)),
    Linux   = b(TO_STRING(__linux__)),
};

С этим приемом, у макросов, которые будут определены, будет истинная стоимость в то время как те, которые не будут определены противоположная стоимость, из-за этого я могу писать следующий код с if constexpr вместо с #ifdef:

int main()
{
    if constexpr (operating_system::Windows)
    {
        // Cosas especificas de Windows
    }
    else if constexpr (operating_system::iOS)
    {
        // Cosas especificas de iOS
    }

    // Cosas independientes de sistema operativo.

    return 0;
}

Мне не нравится быть должным уполномочивать во вспомогательной функции, чтобы переводить стоимость (функция b), но это меньшее зло. Самая большая проблема этой системы состоит в том, что он только способен обнаруживать присутствие макросов, которые начинали бы с низкой схемы (_), дай фальшивые позитивы для макросов, стоимость которых была чем-то, что начиналось бы с низкой схемой (_) и стоимость макроса теряется полностью, так как не существует исчислимая функция во времени компиляции, которая перемещала бы текст в число (ни одна из моих попыток не имела успеха).

Из-за этого следующие макросы (очевидно) не действуют, как он состоит в том, чтобы ждать:

#define _DEBUG 0
#define DRIVERS _09072007

template <int SIZE>
constexpr int i(const char (&definition)[SIZE])
{
    return definition[0] != '_'; // que poner aqui?...
}

enum stuff : int
{
    cpp_version     = i(TO_STRING(__cplusplus)),
    debug_enabled   = i(TO_STRING(_DEBUG)),
    drivers_version = i(TO_STRING(DRIVERS)),
};

int main()
{
    std::cout << "C++ version: "     << stuff::cpp_version << '\n'
              << "Modo debug: "      << stuff::debug_enabled << '\n'
              << "Drivers version: " << stuff::drivers_version << '\n';

    return 0;
}

Предыдущий код показывает:

C++ version: 1
Modo debug: 1
Divers verson: 0

Когда идеальное состояло бы в том, чтобы показать:

C++ version: 201500
Modo debug: 0
Divers verson: _09072007

Ввиду того, что __cplusplus у него есть числовая стоимость, которая не начинается с низкой схемой (_), он получает стоимость 1. В макрос _DEBUG он перемещает то же самое его: у него есть стоимость 0, что был бы как считение, что мы не в способе debug, но он получает стоимость 1. Случается наоборот с макросом DRIVERS, что, начавшись с низкой схемой, получает стоимость 0.

Вопрос.

Существует какой-то способ получать желанный вывод? Была бы необходимой как минимальной одна constexpr что перешел буквальные из текста в число.

Что я попробовал?.

Я попробовал перекурсивную функцию, но индексировать буквального текста не постоянное выражение (даже с индексами, известными во время компиляции).

constexpr int power10(int n)
{
    if (n == 0)
        return 1;

    return 10 * power10(n - 1);
}

template <int SIZE>
constexpr int v(const char (&definition)[SIZE], int INDEX)
{
    // error: 'definition' no es una expresion constante
    constexpr char c = definition[INDEX];


    if (INDEX >= 0)
    {
        if constexpr (c >= '0' && c <= '9')
        {
            return v(definition, INDEX - 1) + (power10(SIZE - INDEX - 2) * (c - '0'));
        }
        else
        {
            return 0 + v(definition, INDEX - 1);
        }
    }

    return 0;
}

template <int SIZE>
constexpr int f(const char (&definition)[SIZE])
{
    return v(definition, SIZE - 2);
}

enum operating_system : bool
{
    // error: valor de el enumerador para 'iOS' no es una constante integral
    iOS     = f(TO_STRING(__APPLE__)),
    // error: valor de el enumerador para 'Windows' no es una constante integral
    Windows = f(TO_STRING(__MINGW32__)),
    // error: valor de el enumerador para 'Linux' no es una constante integral
    Linux   = f(TO_STRING(__linux__)),
};
5
задан 28.02.2017, 13:50
0 ответов