假设我使用构造函数Foo
编写了一个类Foo(int)
。
我有这段代码:
Foo a(i), b = a + Foo(2);
如果我用代码调用代码中的构造函数,例如Foo(2)
,编译器是运行一次并将结果存储为运行时,还是在运行时执行?结构/类是否只包含POD数据类型是否相同?
假设它在运行时执行(我认为是这种情况),有没有办法让它在编译时运行,或者具有与它本身运行时相同的效果?
编辑:恐怕我没有说清楚。我指的是代码的Foo(2)
部分,它是完全不可变的。此外,我无法使用C ++ 11(我正在使用GCC 4.1而无法升级),因此constexpr
虽然有效,但不适合我。
答案 0 :(得分:3)
有可能让a
使用constant initialization
,这是静态初始化,但要实现这一点:
i
大部分是常量表达Foo::Foo(int)
必须为constexpr
Foo:Foo(int)
使用的任何/所有其他功能/ ctors也必须为constexpr
。您的b
- Foo(2)
必须是constexpr
,Foo::operator+(Foo const &)
或Foo operator+(Foo const &, Foo const &)
(以您为准)必须是constexpr
。
如果您想更详细地研究,常量表达式的定义在C ++ 11标准的第5.19节。我的直接猜测是,如果Foo
相当简单,那么a
可能就有可能,但我对b
的确不太确定。
答案 1 :(得分:3)
假设我用构造函数Foo(int)编写了一个类Foo。我有这段代码:
Foo a(i), b = a + Foo(2);
如果我使用常量调用代码中的构造函数,编译器是否运行一次,并将结果存储为运行时,还是在运行时执行?
这有两个层次:
i
是否为编译时常量?如果没有,并且传递给i
的{{1}}的值会影响其行为(无论是影响数据成员值还是影响日志记录等副作用),那么很明显,在编译时构造Foo(i)本身是不可能的。如果Foo::Foo(i)
是常量,那么它本身可能仍然是不可能的 - 例如构造函数实现可能具有基于当前时间的行为,或者需要查阅其他一些运行时数据。这些问题也可能阻止i
在编译时进行评估。
如果Foo(2)
是常量,并且i
的构造函数不依赖于其他仅运行时数据,则可能进行优化。但是,您的代码中没有任何内容要求C ++标准甚至尝试任何优化,更不用说能够优化它了。在Foo
上调用的+
运算符也是如此......优化可能是合法的,但肯定不是必需的。
实际上,我希望大多数当前的主流编译器能够针对编译时常量Foo
优化Foo(i)
的简单情况,但是要通过解决加法来挑战。如果您真的想知道,请在各种优化级别为您的编译器尝试....
假设它在运行时执行(我认为是这种情况),有没有办法让它在编译时运行,或者具有与它本身运行时相同的效果?
是的......你可能会从i
中获得一些内容,这是一个用C ++ 11引入的关键字,它告诉编译器在编译时需要解析某些值(如果你{{1}对于编译器在编译时不需要支持的变量/值,它将报告错误。)
其次,通常可以使用模板表达编译时操作。为了让自己从这个方向开始,您可能希望搜索“C ++模板阶乘编译时”或类似内容,以了解如何编码基本计算。
答案 2 :(得分:2)
“as-if”规则适用,表示编译器可以执行任何喜欢的操作,前提是程序的可观察行为与标准中描述的相同。
如果:
Foo
的构造函数在TU中可见,~Foo
,operator+
是可见的,并且没有做任何事情让RHS的地址“逃脱”为未知代码,或者使用其地址进行可观察行为(例如打印出来)或做其他事情这要求对象实际存在,然后一个足够聪明的优化器可以完全消除Foo(2)
临时值,并且只要operator+
使用RHS的数据成员,只需使用它知道这些成员将拥有的任何值。
或者,作为较小的优化,它可以将值放入程序的数据部分中Foo
的实例的布局中,并将其用作Foo(2)
。我想这就是为运行时存储结果的意思。
这种优化是否实际发生是完全特定于实现的,并且取决于您使用的编译器和标志。反汇编代码,看看到底发生了什么。
如果您执行以下操作,则可以确保{C} 03中只计算Foo(2)
一次{/ 1}}:
static Foo foo2(2);
Foo a(i), b = a + foo2;
foo2
是(根据标准)在运行时计算的,第一次执行代码。同样,编译器可以调用“as-if”规则在编译时执行部分或全部计算,但同样不需要这样做。
答案 3 :(得分:0)
Foo a(i), b = a + Foo(2);
此初始化在运行时发生,而不是在编译时发生。
编译时初始化只发生在内置类型中,如果它们的初始化程序可以在编译时计算,或者它们被声明为全局变量,或者static
。在后两种情况下,它们在编译时是零初始化的。我在这里详细解释了这一点:
答案 4 :(得分:0)
可以在执行过程中的不同点调用已编译的代码。编译代码后,Foo(2)的值可能是不可变的。
答案 5 :(得分:-1)
这在运行时发生。如果您希望它在编译时发生,那么您需要对该值进行硬编码。