1

假设我Foo用构造函数编写了一个类Foo(int)。我有这段代码:

Foo a(i), b = a + Foo(2);

如果我在代码中使用常量调用构造函数,例如Foo(2),编译器是运行一次并存储运行时的结果,还是在运行时执行?结构/类是否仅包含 POD 数据类型是否相同?

假设它在运行时执行(我相信是这种情况),有没有办法让它在编译时运行,或者具有与运行时相同的效果?

编辑:恐怕我没有说清楚。我指的Foo(2)是代码部分,它是完全不可变的。另外,我无法使用 C++11(我正在使用 GCC 4.1 并且无法升级),因此constexpr虽然有效,但不适合我。

4

6 回答 6

3

Let's say I write a class Foo with a constructor Foo(int). And I have this piece of code:

Foo a(i), b = a + Foo(2);

If I call the constructor in the code with a constant, does the compiler run it once, and store the result for run-time, or is it executed at run-time?

There are two levels to this:

  • is it possible and legal w.r.t. the Standard for a perfect optimiser -- achieving everything an expert person could potentially do with unlimited effort and genius - to do this at compile time, and
  • is compile-time behaviour required / guaranteed by the Standard.

Is i a compile time constant? If not, and the value of i passed to Foo::Foo(i) influence its behaviour (whether affecting data member values or side-effects like logging), then clearly it's inherently impossible to construct Foo(i) at compile time. If i is constant, it may still be inherently impossible - for example the constructor implementation may have behaviour based on the current time, or need to consult some other run-time data. Such problems may also prevent Foo(2) being possible to evaluate at compile-time.

If i is constant, and Foo's constructor doesn't depend on other runtime-only data, then it is possible to optimise. But, there's nothing in your code that requires the C++ Standard to even attempt any optimisation, let alone be capable of optimising this away. The same is true of the + operator invoked on the Foos... it may be legal to optimise, but is certainly not required.

In practice, I would expect most current mainstream compiler to optimise simple cases of Foo(i) for compile-time constant i, but be challenged by resolving the addition. If you really want to know, try it for your compiler at various optimisation levels....

Assuming that it executes at run-time (which I believe to be the case), is there a way to make it run at compile-time, or have the same effects as if it were run as such?

Yes... you may get some milage out of constexpr, which is a keyword introduced with C++11 that tells the compiler it's required to resolve certain values at compile time (if you constexpr for variables/values that the compiler isn't required to support at compile time it will report an error).

Secondly, it's often possible to express compile time operations using templates. To get yourself started in that direction, you may want to search for "C++ template factorial compiletime" or similar to see how basic calculations can be coded.

于 2012-05-24T06:42:07.453 回答
3

您可以a使用constant initialization静态初始化,但要做到这一点:

  1. i大多数是一个常量表达式
  2. Foo::Foo(int)一定是constexpr
  3. 使用的任何/所有其他函数/ctorsFoo:Foo(int)也必须是constexpr.

你的情况也差不多b-Foo(2)必须是constexpr,并且Foo::operator+(Foo const &)or Foo operator+(Foo const &, Foo const &)(无论你有什么)都必须是constexpr

常量表达式的定义在 C++11 标准的 §5.19 中,以防您想更详细地研究。我的直接猜测是,如果Foo相当简单,它可能是可能的a,但我不太确定b

于 2012-05-24T05:19:50.753 回答
2

“as-if”规则适用,它表示编译器可以做任何它喜欢的事情,只要程序的可观察行为与标准中描述的行为相同。

如果:

  • 的构造函数Foo在 TU 中可见,
  • 析构函数也是如此~Foo
  • 它们都没有任何副作用,
  • 他们的结果不依赖于任何需要在运行时计算出来的东西(比如时间,或者我们所知道的一些非常量对象的值,这些对象可能在你的代码执行时被修改了),
  • operator+是可见的,并且不会做任何事情让 RHS 的地址“逃逸”到未知代码中,或将其地址用于可观察的行为(例如将其打印出来),或做任何其他需要对象实际存在的事情,

然后一个足够聪明的优化器可以完全消除Foo(2)临时,并且无论在哪里operator+使用 RHS 的数据成员,只要使用它知道这些成员将拥有的任何值。

或者,作为较小的优化,它可以将值放入Foo程序数据部分中的实例的布局中,并将其用作Foo(2). 我想这就是存储运行时结果的意思。

这种优化是否真的发生完全是特定于实现的,并且取决于您使用的编译器和标志。反汇编代码以查看实际发生的情况。

如果您执行以下操作,您可以确保Foo(2)在 C++03 中只计算一次:

static Foo foo2(2);
Foo a(i), b = a + foo2;

foo2是(根据标准)在运行时计算,即第一次执行代码。同样,编译器可以调用“as-if”规则在编译时执行部分或全部计算,但这也不是必需的。

于 2012-05-24T08:52:00.263 回答
0

编译好的代码在执行过程中可能会在不同的时间点被调用。编译代码后,Foo(2) 的值可能是不可变的。

于 2012-05-24T05:06:11.043 回答
0
Foo a(i), b = a + Foo(2);

此初始化发生在运行时,而不是编译时。

编译时初始化仅适用于内置类型,如果它们的初始化器可以在编译时计算,或者如果它们被声明为全局变量,或者声明为static. 在后两种情况下,它们在编译时被初始化为零。我在这里详细解释了这一点:

于 2012-05-24T05:03:58.207 回答
-1

这发生在运行时。如果您希望它在编译时发生,那么您需要对值进行硬编码。

于 2012-05-24T05:05:08.433 回答