【问题标题】:Is it possible to declare auto variables with an if?是否可以使用 if 声明自动变量?
【发布时间】:2019-03-27 12:07:38
【问题描述】:

我的代码如下。

struct conv{
    struct des
    {
        des(int a) {}
        des(int a, int b) {}
        des(int a, int b, int c) {}
    };
};
int main(int argc, const char * argv[]) {

int a = 1;
int b = 1;
int c = 1;

if (a > 1)
{
    auto conv_desc = conv::des(1, 2, 3);
} else if(b > 1) {
    auto conv_desc = conv::des(1, 2);
} else {
    auto conv_desc = conv::des(1);
}
    return 0;
}

代码的模式是从 mkldnn 中提取的。我唯一想做的就是将 auto conv_desc 从 if-else 语句中取出。 我试图从 if-else 语句中声明 auto conv_desc 。 它发生了一个错误: 声明

推导类型为“auto”的变量“conv_desc”需要初始化器

或者如果我使用下面的指针,我得到一个空指针。

另一种方式出错:

获取 'conv::des' 类型的临时对象的地址

如果我不能解决这个问题,我将不得不在每个分支中编写一大段重复代码。

【问题讨论】:

  • 切勿将错误粘贴为图片。
  • 请正确格式化您的代码。
  • 在第二个代码中,每个构造的conv::des将在每个if块的末尾被破坏。
  • conv_desc 是一个指针,为什么不将其定义为 conv::des conv_desc 类型并根据您的 if/else 逻辑进行分配。
  • @PasserBy,那么你如何表达错误。如果您有想法,请帮我编辑。

标签: c++ auto


【解决方案1】:

将您的 if 代码移动到单独的函数中:

conv::des make_des(int a, int b) {
  if (a > 1) {
    return conv::des(1, 2, 3);
  } else if(b > 1) {
    return conv::des(1, 2);
  } else {
    return conv::des(1);
  }
}

int main(int argc, const char * argv[]) {
  int a = 1;
  int b = 1;
  int c = 1;
  auto conv_desc = make_des(a, b);
  return 0;
}

【讨论】:

    【解决方案2】:

    不要使用自动。如果你需要声明一个变量并且还不能赋值,那么就不能使用auto。

    int main(int argc, const char * argv[]) {
        // ...
        conv::des conv_desc; // calls default constructor.
    
        if (a > 1)
        {
            conv_desc = conv::des(1, 2, 3);
        } else if(b > 1) {
            conv_desc = conv::des(1, 2);
        } else {
            conv_desc = conv::des(1);
        }
        // conv_desc is initialized at this point.
        return 0;
    }
    

    你不能使用这样的指针

    int *a;
    { // new scope
        int b = 5;
        a = &b; // error.
    }
    // b is no longer in scope here
    

    b 超出范围时,a 将指向b 曾经所在的地址,现在不再有效。

    如果你想使用指针,那么你可以使用 new。但是,在这种情况下,您必须事后释放内存。

    int main(int argc, const char** argv)
    {
        conv::des *conv_desc = nullptr; // does not call default constructor.
    
        if (a > 1)
        {
            conv_desc = new conv::des(1, 2, 3);
        } else if(b > 1) {
            conv_desc = new conv::des(1, 2);
        } else {
            conv_desc = new conv::des(1);
        }
        if (conv_desc == nullptr) { /* memory allocation failed */ }
        // conv_desc is initialized at this point.
        // ...
        // remember to delete conv_desc
        if (conv_desc != nullptr) { delete conv_desc; conv_desc = nullptr; }
        return 0;
    }
    

    【讨论】:

    • null 在 C++ 中不存在,使用 nullptr 并且您不必在删除之前检查变量是否为空。
    • 我很确定上次尝试删除值为 \x00 的 ptr 时我遇到了段错误
    • 你在其他地方得到了 UB。
    • @GuillaumeRacicot 您链接的帖子中的每个人都使用NULL 而不是nullptr
    • 这是一个建议编辑的好机会。这些回复大多来自 9 年前。 nullptr 那时还不存在。
    【解决方案3】:

    您也可以使用立即调用的 lambda。这是一种常见的模式,可以让一些变量在其他情况下无法变为 const。

    此解决方案与@yachoor 答案非常相似,但使用了 lambda。

    int main(int argc, const char * argv[]) {
        int a = 1;
        int b = 1;
        int c = 1;
    
        // Kind of an inline function that is called immediately
        auto const conv_desc = [&]{
            if (a > 1) {
                return conv::des(1, 2, 3);
            } else if(b > 1) {
                return conv::des(1, 2);
            } else {
                return conv::des(1);
            }
        }();
        // Parens calls the function
    
        return 0;
    }
    

    【讨论】:

    • 这里不需要任何捕获,只需将ab作为普通参数传递
    • @Caleth 通过捕获传递对于我认为的这个习语来说更清楚。对于参数传递和捕获,完成优化的可能性非常高
    【解决方案4】:

    似乎您使代码过于复杂。目前尚不清楚为什么要以这种方式区分这三个构造函数。为什么不使用这样的默认值隐藏对象内部的复杂性?

    struct conv{
        struct des
        {
            des(int a, int b = 0, int c = 0) {
              if(a > 1) {
                /// do some logic
              } else if(b > 1) {
                // do some logic
              } else {
                // do some logic
              }
    
            }
        };
    };
    int main(int argc, const char * argv[]) {
    
      int a = 1;
      int b = 1;
      int c = 1;
    
      auto conv_desc = conv::des(a, b, c);
    
      return 0;
    }
    

    【讨论】:

      【解决方案5】:

      如果你将if ... else链移到一个单独的函数中,你可以使用return

      struct conv
      {
          struct des
          {
              des(int a) {
              }
      
              des(int a, int b) {
              }
      
              des(int a, int b, int c) {
              }
          };
      };
      
      conv::des make_conv_des(int a, int b)
      {
          if (a > 1) {
              return conv::des(1, 2, 3);
          } else if(b > 1) {
              return conv::des(1, 2);
          } else {
              return conv::des(1);
          }
      }
      
      int main(int argc, const char * argv[]) {
      
          int a = 1;
          int b = 1;
      
          auto conv_des = make_conv_des(a, b);
      
          return 0;
      }
      

      【讨论】:

      • 有人打败了你
      • @FalcoGer 现在,将{ 保持在同一行的人们会吹嘘它更快。 DDD
      • 如何更快?它生成相同的程序集...实际上空格与 c/c++ 中的任何内容都没有关系(当然除了单独的单词)
      • @FalcoGer 我的意思是它可以更快地写出答案并击败将{放在单独一行的人。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2023-04-05
      • 1970-01-01
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      相关资源
      最近更新 更多