Использование количества операторов в функции в качестве константы для выделения памяти - PullRequest
1 голос
/ 01 июня 2019

У меня есть функция, которая выполняет кучу тестов. Всякий раз, когда создается новый тест, функция получает еще одну или две строки. И - результат помещается обратно в массив. Итак, что-то вроде этого (упрощенно):

void foo(int *results) {
    auto index { 0 };

    results[i++] = test_1(some, args, here);
    results[i++] = test_1(some, other_args, here);

    results[i++] = test_2(some, args, here);

    results[i++] = test_3(some, args, here);

    // etc. etc.
}

void bar() {
    auto results = new int/* magic */];
    foo(results);
}

Я хочу использовать количество операторов в этой функции, чтобы выделить место для результатов (строка в bar()). Я не могу использовать динамически перераспределенную структуру, такую ​​как std::vector или список и т. Д., Поскольку я не могу выделить какую-либо память из-за аппаратных ограничений.

Теперь я могу просто посчитать строки вручную - и это будет работать. Но потом, когда бы я ни добавлял другой тест, мне приходилось не забывать обновлять магическую константу.

Есть ли способ подсчета результата, который можно использовать для выражения "магия"?

Примечание. Поскольку я скрупулезный человек без достоинства, я готов прекратить использование макросов.

Ответы [ 2 ]

1 голос
/ 01 июня 2019

Поскольку вы не указали никакой языковой версии, отметили ее с помощью constexpr, я решил эту проблему, используя C ++ 17.Это без каких-либо грязных макросов.Вместо этого я полагаюсь на CTAD (вывод аргументов шаблона конструктора).

Прежде всего, я предположил, что ваши функции являются constexpr.Таким образом, все может быть сделано во время компиляции.(В полученном коде вы даже не видите использования памяти для массива.

constexpr int test_1(int a, int b, int c)
{
    return a + b + c;
}

constexpr int test_2(int a, int b, int c)
{
    return a * b * c;
}

Это не является строго необходимым, однако, это может переместить ненужные вычисления для компиляции времени. Это также позволяет распространятьconstexpr до конечной переменной. Таким образом, вы можете гарантировать, что ни один из вычислений не будет выполнен во время выполнения.

static constexpr auto myArr = createFilledArray();

Однако наиболее важной частью является CTAD. Новый C ++ 17функция, которая позволяет вывести аргументы шаблона вашего класса на основе значений, переданных в конструкторе. Вместо того, чтобы сначала создавать массив, я создаю массив напрямую со всеми различными значениями, которые вы передаете ему. Так как вы не предоставилилюбые аргументы в вашем примере, я предполагаю, что они известны во время компиляции, что снова требуется для водопада constexpr. Однако, что более важно, я предполагаю, что число элементов известно во время компиляции.

Путем построения всехаргументы при вызове конструктора std::array, нет необходимости указывать его шаблонаргументы (обратите внимание также на auto как тип возвращаемого значения).Для этого примера это выводится как std::array<int, 3>.

constexpr auto createFilledArray(){
    std::array a
        {
            test_1(1, 2, 3),
            test_1(4, 5, 6),
            test_2(7, 8, 9),
        };
    return a;
}

int main(int, char**)
{
    return myArr.size(); // Returns 3
}

Код в проводнике компилятора

Из того, что я знаю, есть предложениедля C ++ 20 , который предназначен для создания std::vector constexpr.Тем не менее, ни один из протестированных мной компиляторов не поддерживает это.Это, скорее всего, позволит вам писать код на основе std::vector и использовать его во время компиляции.Другими словами, выделенная память, которая представляет ваши данные, будет частью вашего исполняемого файла.

Быстрая попытка того, как ваш код может выглядеть, можно найти здесь, в проводнике компилятора .(Тем не менее, в данный момент он не компилируется)

1 голос
/ 01 июня 2019

Говоря о взломе макросов:

#include <iostream>

#define ADD_TEST(X) do { results[i++] = (X); (void)__COUNTER__; } while (0)

const int foo_start = __COUNTER__;
void foo(int *results) {
    int i = 0;
    ADD_TEST(100);
    ADD_TEST(200);
    ADD_TEST(300);
}
const int foo_end = __COUNTER__;

int main() {
    int results[foo_end - foo_start - 1];
    foo(results);
    for (int i : results) {
        std::cout << i << '\n';
    }
}

Это немного ужасно и __COUNTER__ - нестандартное расширение в GCC и других компиляторах, но, эй, , оно работает .

Преимущество состоит в том, что он не использует никаких причудливых функций C ++, поэтому в принципе он должен быть совместим со старыми компиляторами и даже с C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...