标签: constexpr

Clang 对递归 constexpr 函数的好奇错过了优化

今天我想测试一下,Clang 如何转换两个函数的递归幂,并注意到即使使用已知指数,即使使用 constexpr 也不会优化递归。

#include <array>
constexpr unsigned int pow2_recursive(unsigned int exp) {
    if(exp == 0) return 1;
    return 2 * pow2_recursive(exp-1);
}

unsigned int pow2_5() {
    return pow2_recursive(5);
}
Run Code Online (Sandbox Code Playgroud)

pow2_5 被编译为对 pow2_recursive 的调用。

pow2_5():                             # @pow2_5()
        mov     edi, 5
        jmp     pow2_recursive(unsigned int)     # TAILCALL
Run Code Online (Sandbox Code Playgroud)

但是,当我在需要在编译时知道结果的上下文中使用结果时,它将在编译时正确计算结果。

unsigned int pow2_5_arr() {
    std::array<int, pow2_recursive(5)> a;
    return a.size();
}
Run Code Online (Sandbox Code Playgroud)

被编译为

pow2_5_arr():                        # @pow2_5_arr()
        mov     eax, 32
        ret
Run Code Online (Sandbox Code Playgroud)

以下是 Godbolt 中完整示例的链接:https ://godbolt.org/z/fcKef1

那么,我在这里错过了什么吗?有什么可以在运行时改变结果的原因吗,pow2_5 不能像 pow2_5_arr 一样优化?

c++ clang compiler-optimization constexpr clang++

5
推荐指数
0
解决办法
65
查看次数

C++ 17 元编程递归结构:enum 或 constexpr

出于说明目的,我展示了两个小的、略有不同的模板化递归定义。一个使用 an enum,另一个使用static constexpr定义一个值。

我检查了两个程序的输出程序集,它们完全相同,并且在语义上它们看起来也相同。

我认为constexpr可能更现代一些,但是使用enum/之间有什么区别static constexpr,或者是否有任何特定用例的区别真的很重要?

// using enum
template<uint64_t N>
struct Sum {
    enum : uint64_t { value = N + Sum<N - 1>::value };
};

template<>
struct Sum<0> {
    enum : uint64_t { value = 1 };
};
Run Code Online (Sandbox Code Playgroud)
// using static constexpr
template<uint64_t N>
struct Sum {
    static constexpr uint64_t value = N + Sum<N - 1>::value;
};

template<>
struct Sum<0> {
    static constexpr uint64_t value = 1; …
Run Code Online (Sandbox Code Playgroud)

c++ enums templates constexpr c++17

5
推荐指数
1
解决办法
203
查看次数

constexpr 函数可以包含标签吗?

这个程序

constexpr void f() { x: ; }
Run Code Online (Sandbox Code Playgroud)

由 gcc 编译,但 clang 说:

error: statement not allowed in constexpr function
Run Code Online (Sandbox Code Playgroud)

那么这个代码有效吗?

c++ language-lawyer constexpr

5
推荐指数
1
解决办法
103
查看次数

我的代码如何在编译时做一件事,而在运行时做另一件事?

我正在实现一个constexpr int foo();功能。在 的主体中foo(),我想在编译时做一些不同的事情(并且可能返回一些不同的东西),而在运行时做一些不同的事情。

使用 C++20,我可以使用std::is_constant_evaluated

constexpr int foo() { return std::is_constant_evaluated() ? 123 : 456 };
Run Code Online (Sandbox Code Playgroud)

但是如果我使用的是 C++17(或更早版本)怎么办 - 我可以用同样的效果做什么?

注意:特定于编译器的解决方案是可以接受的(尽管不太理想)。

c++ constexpr c++17

5
推荐指数
1
解决办法
150
查看次数

寻找初始化为 const int 和 int 的指针的解释

我正在通过 C++ Primer 中的练习进行练习,并找到了练习 2.32 的在线解决方案。

我知道以下代码是非法的,因为初始化无法从 int 转换为 int*:

int null = 0, *p = null;

但是,提到的两个解决方案是我没有提出的:

    const int null3 = 0, *p3 = null3;
    
    constexpr int null4 = 0, *p4 = null4;
Run Code Online (Sandbox Code Playgroud)

为什么在编译期间允许这些没有错误?我仍然期待 p3 和 p4 的初始化需要 & 来表示地址 (&null3, &null4)。

这是我的记事本文件中的代码:


#include <iostream>

int main()
{

//  int null = 0, *p = null; // it is not legal; depending on intent there are two ways to fix (that I can think off atm)

    {
    int null …
Run Code Online (Sandbox Code Playgroud)

c++ pointers initialization constants constexpr

5
推荐指数
1
解决办法
70
查看次数

了解 C++ constexpr 性能

我最近使用constexprC++17 的函数编写了一个编译时光线追踪器。完整的源代码可以在这里看到。此问题的相关代码如下所示:

constexpr auto image = []() {
        StaticImage<image_width, image_height> image;

        Camera camera{Pointf{0.0f, 0.0f, 500.0f},
                      Vectorf{0.0f},
                      Vectorf{0.0f, 1.0f, 0.0f},
                      500.0f};

        std::array<Shapes, 1> shapes_list{Sphere{Pointf{0.0f}, 150.0f}};
        std::array<Materials, 1> materials_list{DefaultMaterial{}};
        ShapeContainer<decltype(shapes_list)> shapes{std::move(shapes_list)};
        MaterialContainer<decltype(materials_list)> materials{
            std::move(materials_list)};

        SphereScene scene;
        scene.set_camera(camera);

        Renderer::render(scene, image, shapes, materials);
        return image;
    }();
Run Code Online (Sandbox Code Playgroud)

其中每个这里示出的类(StaticImageCameraShapesMaterialsShapeContainerMaterialContainer,和SphereScene)由完全constexpr的功能。Renderer::renderconstexpr负责循环图像中的每个像素,将光线射入场景,并设置相应的颜色。

使用当前的设置和 512x512 的图像,在发布模式下使用 MSVC 16.9.2,编译器需要大约 35 分钟来完成生成图像。在此过程中,其内存使用量上升到最终使用近 64GB RAM 的程度。

所以,我的问题是:为什么编译时间和内存使用率这么高?

我的理论是编译时间的部分原因是调用堆栈的复杂性(即大量模板、CRTP 和深度),所以我尝试通过删除几个模板来稍微简化调用堆栈( …

c++ raytracing constexpr c++17

5
推荐指数
1
解决办法
152
查看次数

如果字符串有空格,则引发编译时错误

我有一个基类,打算由我正在编写的代码的其他用户继承,其中一个抽象函数返回对象的名称。由于项目的性质,名称不能包含空格。

class MyBaseClass {

  public:

    // Return a name for this object. This should not include whitespace.
    virtual const char* Name() = 0;

};
Run Code Online (Sandbox Code Playgroud)

有没有办法在编译时检查Name()函数的结果是否包含空格?我知道constexpr函数可以进行编译时操作,但我不确定以正确的方式向代码用户发出信号,告知他们的函数返回一个顽皮的字符串。

我也不清楚如何让constexpr编译器实际执行一个函数来执行这样的检查(如果constexpr是这样的话)。

c++ library-design compile-time constexpr

5
推荐指数
1
解决办法
106
查看次数

为没有模板参数的可变模板递归创建基本情况

我正在尝试将递归与可变参数模板一起使用。我希望基本情况具有零模板参数。在查看了以前问题的 stackoverflow 答案后,我发现了对这个问题的两种回应:

  1. 你不应该专门化模板函数。赫伯·萨特 (Herb Sutter) 在这里写道:http : //www.gotw.ca/publications/mill17.htm
  2. 您使用template <typename = void> template <typename T = void> 。例如,这里的第一个答案:如何编写可变参数模板递归函数?

我试图在我的问题中使用解决方案 (2),但收到错误。这是一个最小的、可重现的示例:

#include <iostream>

template<typename = void> // base case
int NumArguments() {
    return 0;
}

template<typename FirstArg, typename... RemainingArgs>
int NumArguments() {
    return 1 + NumArguments<RemainingArgs...>();
}
Run Code Online (Sandbox Code Playgroud)
class A {
public:
    A() {}
};

int main() {
    std::cout << NumArguments<A>();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在 Microsoft Visual C++20 中编译给出了错误:

 error C2668: 'NumArguments': ambiguous call to overloaded function …
Run Code Online (Sandbox Code Playgroud)

c++ recursion compiler-errors variadic-templates constexpr

5
推荐指数
1
解决办法
177
查看次数

如果 consteval 需要什么?

C++23 将引入if consteval. 这将在哪里使用,它与constexpr if?

c++ constexpr consteval c++23

5
推荐指数
1
解决办法
304
查看次数

为什么我可以在 constexpr 函数中修改 const_cast-ed 对象?

我一直以为:

  • 写入const_casted 变量是 UB
  • constexpr 中不允许使用 UB

所以我很困惑为什么这段代码会编译

constexpr int fn(){
    int v = 42;
    return [v]() {
        const_cast<int&>(v)+=5;
        return v;
    }();
}
static constexpr auto val = fn();
int main() {
    return val;
}
Run Code Online (Sandbox Code Playgroud)

注意:我知道没有理由不允许这样做,因为结果应该是显而易见的,我对为什么允许这样做的法律解释更感兴趣。

c++ undefined-behavior constexpr c++20

5
推荐指数
1
解决办法
92
查看次数