C++ - 我可以创建编译时变量对象吗?

Poe*_*odu 5 c++ variables compile-time constexpr

我最近在使用 constexpr 但我刚刚意识到我用错了它。我很好奇是否可以创建编译时变量(或变量对象)。cppreference.com
的 constexpr 定义告诉我们:

constexpr 说明符声明可以在编译时计算函数或变量的值。

那么为什么下面的代码不正确呢?

#include <iostream>

int main()
{
    constexpr int x = 30;
    x += 10;
    std::cout << x;
}
Run Code Online (Sandbox Code Playgroud)

这个整数可以在编译时完美地求值。我知道编译器可以在没有 constexpr 修饰符的情况下优化这样的变量,但是如果我想要一个编译时对象怎么办?

#include <iostream>

class ctFoo {
public:
    ctFoo()
        : value{ 0 }
    {
    }
    int accumulate(int value_) {
        return (value += value_), value;
    }
    int value;
};

int main()
{
    ctFoo foo;
    std::cout << foo.accumulate(100);
}
Run Code Online (Sandbox Code Playgroud)

我有什么确定性可以确定该代码将在编译时进行评估?我问这个问题是因为我目前正在编写一些 Vector2 和 Vector3 数学,并且我想创建这样的实现,它将能够处理编译时和运行时计算。有可能吗?
谢谢。

编辑

正如 max66 指出的那样,constexpr 意味着 const,但我要问:为什么会这样?现代编译器应该能够在编译时推断出它的值。另外,我知道我可以简单地创建另一个 constexpr 常量(广告最上面的代码示例),但我的问题涉及更复杂的代码。

chr*_*ris 4

那么为什么下面的代码不正确呢?

#include <iostream>

int main()
{
    constexpr int x = 30;
    x += 10;
    std::cout << x;
}
Run Code Online (Sandbox Code Playgroud)

constexpr暗示const。您需要将其限制在constexpr上下文中:

constexpr int foo() {
    int x = 30;
    x += 10;
    return x;
}
Run Code Online (Sandbox Code Playgroud)

但是如果我想要一个编译时对象怎么办?

#include <iostream>

class ctFoo {
public:
    ctFoo()
        : value{ 0 }
    {
    }
    int accumulate(int value_) {
        return (value += value_), value;
    }
    int value;
};
Run Code Online (Sandbox Code Playgroud)

给予constexpr支持:

constexpr ctFoo() : value{ 0 }

constexpr int accumulate(int value_) {
    value += value_;
    return value;
}
Run Code Online (Sandbox Code Playgroud)

您现在拥有的保证是,如果您的ctFoo对象是常量表达式并且您accumulate在函数示例constexpr之类的上下文中调用foo,那么您可以在编译时使用结果。例如:

constexpr int foo() {
    ctFoo f;
    f.accumulate(10);
    return f.value;
}

static_assert(foo() == 10);
Run Code Online (Sandbox Code Playgroud)

或者:

constexpr void accumulate(ctFoo& f) {
    f.accumulate(10);
}

constexpr int foo() {
    ctFoo f;
    accumulate(f);
    return f.value;
}

static_assert(foo() == 10);
Run Code Online (Sandbox Code Playgroud)

这里要记住的关键是运行时评估也是一种选择。如果我将 some 设置ctFoo为运行时值(例如,用户输入),那么在编译时value就不可能发生调用。accumulate但这没关系 - 相同的代码在两种情况下都可以工作。