C++ - 我可以创建编译时变量对象吗?
C++ - Can I create compile-time variable object?
我最近在使用 constexpr,但我才意识到我用错了。我很好奇我是否可以创建一个编译时变量(或变量对象)。
来自 cppreference.com 的 constexpr 定义告诉我们:
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.
为什么下面的代码不正确?
#include <iostream>
int main()
{
constexpr int x = 30;
x += 10;
std::cout << x;
}
这个整数可以在编译时完美求值。我知道编译器可以在没有 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);
}
我有什么把握,这段代码将在编译时求值?
我问这个,因为我目前正在写一些 Vector2 和 Vector3 数学,我想创建这样的实现,它将能够处理编译时和 运行-time 计算。有可能吗?
谢谢
编辑
正如 max66 指出的那样,constexpr 意味着 const,但我要问:为什么这样?现代编译器应该能够在编译时推断出它的价值。
另外,我知道我可以简单地创建另一个 constexpr 常量(广告。最上面的代码示例),但我的问题涉及更复杂的代码。
您需要继续阅读:
A constexpr
specifier used in an object declaration implies const
.
您无法更改 constexpr
,这就是您能够在常量表达式中使用它的全部意义所在。
接下来要考虑的是您似乎混合了两种不同的上下文。我毫不怀疑编译器将能够完全优化您的最后一个示例,但那是 constexpr
所做的其他事情。关键字表示它所表示的 可以 在编译时进行评估,但不一定如此。因此,您可以编写一个 constexpr
函数,其中的所有内容都可能在编译时进行评估,并且仍然可以在 运行 时运行。
只有当您处于编译时上下文中时,您才能真正拥有可以在编译时评估的对象(因此没有优化器)并且您可以修改。例如,您在 constexpr
函数中处于这样的上下文中:
constexpr int foo() {
int a = 10;
++a; // I can modify a.
return a;
// even if I did this: int Array[foo()];
}
但是你在一个普通的函数中没有这样的能力,语言就是不允许。
所以,回答你的问题:
What certainty I have, that this code will be evaluated in compile-time?
您没有,因为您没有使用 constexpr
。即便如此,如果您在不需要编译时评估的地方调用 constexpr
函数,该函数可能会在 运行 时间被调用,
Is it even possible?
当然,如前所述,您创建了一个 constexpr
函数,如果需要,它将在编译时进行评估。
So why is following code incorrect?
#include <iostream>
int main()
{
constexpr int x = 30;
x += 10;
std::cout << x;
}
constexpr
表示 const
。您需要将其限制在 constexpr
上下文中:
constexpr int foo() {
int x = 30;
x += 10;
return x;
}
But what if I want to have a compile-time object?
#include <iostream>
class ctFoo {
public:
ctFoo()
: value{ 0 }
{
}
int accumulate(int value_) {
return (value += value_), value;
}
int value;
};
给它constexpr
支持:
constexpr ctFoo() : value{ 0 }
constexpr int accumulate(int value_) {
value += value_;
return value;
}
您现在拥有的保证是,如果您的 ctFoo
对象是常量表达式,并且您在 constexpr
上下文中调用 accumulate
,如 foo
函数示例,然后你可以在编译时使用结果。例如:
constexpr int foo() {
ctFoo f;
f.accumulate(10);
return f.value;
}
static_assert(foo() == 10);
或:
constexpr void accumulate(ctFoo& f) {
f.accumulate(10);
}
constexpr int foo() {
ctFoo f;
accumulate(f);
return f.value;
}
static_assert(foo() == 10);
这里要记住的关键是运行时评估也是一个选项。如果我将某些 ctFoo
的 value
设置为运行时值(例如,用户输入),那么 accumulate
调用不可能在编译时发生。但这没关系 - 相同的代码在两种情况下都有效。
我最近在使用 constexpr,但我才意识到我用错了。我很好奇我是否可以创建一个编译时变量(或变量对象)。
来自 cppreference.com 的 constexpr 定义告诉我们:
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.
为什么下面的代码不正确?
#include <iostream>
int main()
{
constexpr int x = 30;
x += 10;
std::cout << x;
}
这个整数可以在编译时完美求值。我知道编译器可以在没有 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);
}
我有什么把握,这段代码将在编译时求值?
我问这个,因为我目前正在写一些 Vector2 和 Vector3 数学,我想创建这样的实现,它将能够处理编译时和 运行-time 计算。有可能吗?
谢谢
编辑
正如 max66 指出的那样,constexpr 意味着 const,但我要问:为什么这样?现代编译器应该能够在编译时推断出它的价值。 另外,我知道我可以简单地创建另一个 constexpr 常量(广告。最上面的代码示例),但我的问题涉及更复杂的代码。
您需要继续阅读:
A
constexpr
specifier used in an object declaration impliesconst
.
您无法更改 constexpr
,这就是您能够在常量表达式中使用它的全部意义所在。
接下来要考虑的是您似乎混合了两种不同的上下文。我毫不怀疑编译器将能够完全优化您的最后一个示例,但那是 constexpr
所做的其他事情。关键字表示它所表示的 可以 在编译时进行评估,但不一定如此。因此,您可以编写一个 constexpr
函数,其中的所有内容都可能在编译时进行评估,并且仍然可以在 运行 时运行。
只有当您处于编译时上下文中时,您才能真正拥有可以在编译时评估的对象(因此没有优化器)并且您可以修改。例如,您在 constexpr
函数中处于这样的上下文中:
constexpr int foo() {
int a = 10;
++a; // I can modify a.
return a;
// even if I did this: int Array[foo()];
}
但是你在一个普通的函数中没有这样的能力,语言就是不允许。
所以,回答你的问题:
What certainty I have, that this code will be evaluated in compile-time?
您没有,因为您没有使用 constexpr
。即便如此,如果您在不需要编译时评估的地方调用 constexpr
函数,该函数可能会在 运行 时间被调用,
Is it even possible?
当然,如前所述,您创建了一个 constexpr
函数,如果需要,它将在编译时进行评估。
So why is following code incorrect?
#include <iostream> int main() { constexpr int x = 30; x += 10; std::cout << x; }
constexpr
表示 const
。您需要将其限制在 constexpr
上下文中:
constexpr int foo() {
int x = 30;
x += 10;
return x;
}
But what if I want to have a compile-time object?
#include <iostream> class ctFoo { public: ctFoo() : value{ 0 } { } int accumulate(int value_) { return (value += value_), value; } int value; };
给它constexpr
支持:
constexpr ctFoo() : value{ 0 }
constexpr int accumulate(int value_) {
value += value_;
return value;
}
您现在拥有的保证是,如果您的 ctFoo
对象是常量表达式,并且您在 constexpr
上下文中调用 accumulate
,如 foo
函数示例,然后你可以在编译时使用结果。例如:
constexpr int foo() {
ctFoo f;
f.accumulate(10);
return f.value;
}
static_assert(foo() == 10);
或:
constexpr void accumulate(ctFoo& f) {
f.accumulate(10);
}
constexpr int foo() {
ctFoo f;
accumulate(f);
return f.value;
}
static_assert(foo() == 10);
这里要记住的关键是运行时评估也是一个选项。如果我将某些 ctFoo
的 value
设置为运行时值(例如,用户输入),那么 accumulate
调用不可能在编译时发生。但这没关系 - 相同的代码在两种情况下都有效。