我想编写有条件编译的代码,并根据以下两种情况编写:
CASE_A:
for(int i = 1; i <= 10; ++i){
// do something...
}
CASE_B:(==!CASE_A)
{
const int i = 0;
// do something...
}
也就是说,在情况A中,我希望有超过可变正常回路i
,但在情况B中,我想限制本地作用域变量i
,以仅一种特殊情况(这里指定作为i = 0
)。显然,我可以写一些内容:
for(int i = (CASE_A ? 1 : 0); i <= (CASE_A ? 10 : 0); ++i){
// do something
}
不过,我不喜欢这个设计,因为它不会让我趁const
声明中的特殊情况B.这样的声明可能会允许大量优化的,因为这循环的主体通过其i
的常量值替换i
的潜在编译时间大大受益。
期待社区提供有关如何有效实现这一目标的任何提示。
谢谢!
编辑:
可以在编译时评估CASE_A和CASE_B。
i
未作为参考传递
const
是不能在体内(否则{{1}}就没有意义)重新评估,但我不知道,编译器将通过证明这种努力
答案 0 :(得分:7)
假设你没有过度简化你的例子,那应该没关系。假设CASE_A可以在编译时进行评估,代码为:
for( int i = 0; i <= 0; ++i ) {
do_something_with( i );
}
将生成与:
相同的机器代码const int i = 0;
do_something_with( i );
对于任何体面的编译器(当然,优化已打开)。
在研究这个问题时,我发现这里有一个很好的观点。如果i
通过指针或引用传递给函数,则编译器不能认为它不会更改。即使指针或引用是const
,也是如此! (因为const
可以在函数中抛弃。)
答案 1 :(得分:2)
似乎是一个明显的解决方案:
template<int CASE>
void do_case();
template<>
void do_case<CASE_A>()
{
for(int i = 1; i <= 10; ++i){
do_something( i );
}
}
template<>
void do_case<CASE_B>()
{
do_something( 0 );
}
// Usage
...
do_case<CURRENT_CASE>(); // CURRENT_CASE is the compile time constant
答案 2 :(得分:1)
如果您的CASE_B / CASE_B确定可以表示为编译时常量,那么您可以使用类似下面的内容以一种漂亮,可读的格式执行您想要的操作(这只是您使用{{{ 1}}运算符用于?:
循环初始化和条件):
for
这清楚地表明enum {
kLowerBound = (CASE_A ? 1 : 0),
kUpperBound = (CASE_A ? 10 : 0)
};
for (int i = kLowerBound; i <= kUpperBound; ++i) {
// do something
}
循环边界是编译时常量 - 请注意,我认为即使在for
表达式直接用于{?:
表达式,今天大多数编译器也没有问题。 {1}}声明的控制条款。但是,我认为使用枚举使人们阅读代码更加明显。
同样,今天任何有价值的编译器都应该认识到for
在循环中是不变的,并且在i
情况下也确定循环永远不会迭代。使CASE_B
i
无法使编译器的优化可能性受益。
如果您确信如果const
为i
,编译器可能能够更好地进行优化,那么简单的修改可以提供帮助:
const
我怀疑这会对编译器有多大帮助(但检查它的输出 - 我可能是错的)如果for (int ii = kLowerBound; ii <= kUpperBound; ++ii) {
const int i = ii;
// do something
}
未被修改或者其地址被采用(即使将其作为参考传递)。但是,它可能有助于您确保i
未被不恰当地修改或通过循环中的引用/地址传递。
另一方面,如果在其上使用i
修饰符,您可能会看到编译器产生的优化带来的好处 - 在const
的地址被采用的情况下或{ {1}}被抛弃,编译器仍被允许将i
视为未在其生命周期内被修改。抛弃const
的东西可能造成的任何修改都是未定义的行为,因此允许编译器忽略它们可能发生的行为。当然,如果您有可能执行此操作的代码,那么您需要比优化更大的担忧。因此,确保i
没有“背后”修改尝试比仅仅将const
标记为i
'以进行优化更为重要,更重要的是使用{{1}可能会帮助您确定是否进行了修改(但请记住,强制转换可以继续隐藏)。
答案 3 :(得分:0)
我不太确定这是你正在寻找的,但我正在使用vanilla FOR循环的这个宏版本强制循环计数器为const
以捕获它的任何修改在身体
#define FOR(type, var, start, maxExclusive, inc) if (bool a = true) for (type var##_ = start; var##_ < maxExclusive; a=true,var##_ += inc) for (const auto var = var##_;a;a=false)
用法:
#include <stdio.h>
#define FOR(type, var, start, maxExclusive, inc) if (bool a = true) for (type var##_ = start; var##_ < maxExclusive; a=true,var##_ += inc) for (const auto var = var##_;a;a=false)
int main()
{
FOR(int, i, 0, 10, 1) {
printf("i: %d\n", i);
}
// does the same as:
for (int i = 0; i < 10; i++) {
printf("i: %d\n", i);
}
// FOR catches some bugs:
for (int i = 0; i < 10; i++) {
i += 10; // is legal but bad
printf("i: %d\n", i);
}
FOR(int, i, 0, 10, 1) {
i += 10; // is illlegal and will not compile
printf("i: %d\n", i);
}
return 0;
}