1

我有一个执行一堆测试的函数。每当创建一个新测试时,该函数就会多得到一两行。并且 - 结果被推回数组中。所以它是这样的(简化):

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())。我不能使用动态重新分配的结构,如 anstd::vector或 list 等 - 因为由于硬件限制,我无法分配任何内存。

现在,我可以手动计算行数 - 这会起作用。但是每当我添加另一个测试时,我都必须记住更新神奇的常数。

有没有办法用可用于“魔术”表达式的结果进行计数?

注意:由于我是一个没有尊严的严谨的人,我愿意屈从于使用宏。

4

2 回答 2

1

但是,由于您没有指定任何语言版本,因此使用 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::vectorconstexpr。但是,我在编译器资源管理器中测试过的编译器都不支持这一点。这很可能允许您在编译时基于它编写代码std::vector并使用它。换句话说,代表您的数据的分配内存将成为您的可执行文件的一部分。

可以在编译器资源管理器中找到您的代码的快速尝试。(但是,此时它还没有编译)

于 2019-06-01T15:24:32.927 回答
1

说到宏黑客:

#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 兼容。

于 2019-06-01T11:43:02.900 回答