Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;使用'const int'作为循环变量?_C++_Conditional Compilation - Fatal编程技术网

C++ C++;使用'const int'作为循环变量?

C++ C++;使用'const int'作为循环变量?,c++,conditional-compilation,C++,Conditional Compilation,我想编写根据以下两种情况有条件编译的代码: 案例A: for(int i = 1; i <= 10; ++i){ // do something... } 也就是说,在案例A中,我希望在变量I上有一个正常的循环,但在案例B中,我希望将局部作用域变量I仅限于特殊情况(此处指定为I=0)。显然,我可以写一些大致的东西: for(int i = (CASE_A ? 1 : 0); i <= (CASE_A ? 10 : 0); ++i){

我想编写根据以下两种情况有条件编译的代码:

案例A:

    for(int i = 1; i <= 10; ++i){
        // do something...
    }
也就是说,在案例A中,我希望在变量
I
上有一个正常的循环,但在案例B中,我希望将局部作用域变量
I
仅限于特殊情况(此处指定为
I=0
)。显然,我可以写一些大致的东西:

    for(int i = (CASE_A ? 1 : 0); i <= (CASE_A ? 10 : 0); ++i){
         // do something
    }

for(int i=(CASE_A?1:0);i假设您没有过度简化示例,这不重要。假设CASE_A可以在编译时计算,代码:

for( int i = 0; i <= 0; ++i ) {
    do_something_with( i );
}
对于任何像样的编译器(当然,在打开优化的情况下)


在研究这一点时,我发现这里有一个很好的观点。如果
I
通过指针或引用传递给函数,编译器不能假设它没有改变。即使指针或引用是
const
!(因为
const
可以在函数中丢弃)似乎是显而易见的解决方案:

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
模板
void do_case();
模板
void do_case()
{

对于(int i=1;i如果您的CASE_B/CASE_B确定可以表示为编译时常量,那么您可以使用如下类似的内容以一种好的可读格式执行您想要的操作(这只是使用
?:
操作符进行
循环初始化和条件的示例的一个变体):

如果
I
未被修改或其地址被占用(即使将其作为引用传递),我怀疑这会对编译器有多大帮助(但检查它的输出-我可能是错的)。但是,它可能会帮助您确保
I
未被不适当地修改或在循环中通过引用/地址传递


另一方面,如果在编译器上使用
const
修饰符,您实际上可能会看到编译器产生的优化带来的好处-在
i
的地址被取下或
const
被丢弃的情况下,编译器仍然可以在其生存期内将
i
视为未被修改。任何mod丢弃
const
的东西可能进行的引用是未定义的行为,因此编译器可以忽略它们可能发生的情况。当然,如果你有可能这样做的代码,你会比优化更担心。因此,更重要的是确保没有“幕后”修改尝试
i
而不是简单地将
i
标记为
const
“进行优化”,但使用
const
可能会帮助您确定是否进行了修改(但请记住,强制转换可以继续隐藏该修改).

我不太确定这是否是您要寻找的,但我使用的是vanilla for循环的这个宏版本,它强制循环计数器为
常量
,以捕获身体中对它的任何修改

#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)
#为(type,var,start,maxExclusive,inc)定义if(bool a=true)为(type var###########inc)为(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;
}
#包括
#定义(type,var,start,maxExclusive,inc)if(bool a=true)FOR(type var########(var######u=start;var######(a=false)FOR(const auto var######
int main()
{
FOR(int,i,0,10,1){
printf(“i:%d\n”,i);
}
//是否与以下内容相同:
对于(int i=0;i<10;i++){
printf(“i:%d\n”,i);
}
//对于一些bug:
对于(int i=0;i<10;i++){
i+=10;//合法但不好
printf(“i:%d\n”,i);
}
FOR(int,i,0,10,1){
i+=10;//是非法的,不会编译
printf(“i:%d\n”,i);
}
返回0;
}

从实用的角度来看,如果解决方案适合整体语义,例如通过一个
#define Smart_Loop(i)….
宏,该宏将用作:
for(Smart_Loop(i)){…}
说真的,我打赌在任何情况下,不管你如何定义,你的小循环都会展开或优化。如果你不带地址,每个有能力的编译器都可以删除
int I
。与
const int I
一样,只有你不带地址,它才能被删除。I sp我希望编译器能够为您优化这个案例。因此,您应该编写最易于阅读和维护的代码。我想问题是:“是吗?”编译器需要证明
i
在循环体中没有改变,这可能是显而易见的,也可能不是因为循环体中的代码复杂。然后让你的代码更简单,让其他人和编译器都能阅读!这样它就确切地知道你在做什么,并且可以为你优化它。公平地说,任何如果
i
被声明为
const
@Daniel-100%同意这个原则,那么阻止编译器知道
i
将要更改,就会产生错误!但是,在实践中,这意味着编写
if(CASE_A){…x..}else{…same x..}
这个
x
可能有1000行,所以我不确定这样写是否符合“更简单”的条件。问题是,为什么是x,1000行!!?如果任何东西超过几百行代码,它可能应该被抽象为子方法,编译器可以决定它是否值得使用(在这种情况下很可能会这样做);因此,您有了干净的代码!我知道使用模板可以很好地实现编译时析取。但是这会导致构建两个独立的
void do_something(const int I);
函数:通用函数和专用
I=0
变量吗?
enum {
    kLowerBound = (CASE_A ? 1 : 0),
    kUpperBound = (CASE_A ? 10 : 0)
};

for (int i = kLowerBound; i <= kUpperBound; ++i) {
    // do something
}
for (int ii = kLowerBound; ii <= kUpperBound; ++ii) {
    const int i = ii;

    // do something
}
#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;
}