【问题标题】:C++11 conditional data typeC++11 条件数据类型
【发布时间】:2021-08-04 17:22:12
【问题描述】:

我编写了一个有条件地初始化对象的 C++11 函数。考虑以下示例:

arma::mat some_function(bool a, bool b, unsigned long int c) {
  if(a) {
    if(b) {
      arma::sp_mat d(c, c);
    } else {
      arma::SpMat<short> d(c, c);
    }
  } else {
    if(b) {
      arma::mat d(c, c, fill::zeros);
    } else {
      arma::Mat<short> d(c, c, fill::zeros);
    }
  }
  // Some other computations and a return statement
}

如您所见,我想初始化一个对象d,其中(犰狳)数据类型取决于布尔值ab。不幸的是,它无法编译,编译器抱怨 d 没有在随后使用的范围内声明。

我发现了关于类似问题的各种讨论。条件初始化显然是在 C++17 中引入的。但是,我需要在这个应用程序中使用 C++11。其他建议提到 type_traits 库和 lambda 函数。许多讨论集中在有条件地指定对象的内容而不是其数据类型。由于我对 C++ 还很陌生,我不确定如何将这些选项中的任何一个应用到这个嵌套的条件结构中。

【问题讨论】:

  • 您初始化的那些名为d 的变量都在一行代码的范围内。但是您的大问题是这些变量具有不同的类型,您希望d 的类型是什么?
  • 一个类型只能依赖于编译时常量,比如模板参数。不能依赖函数参数。
  • std::variant 从 C++17 派生自 boost::variant。那会奏效的。

标签: c++ c++11 types initialization armadillo


【解决方案1】:

您可能需要将通用代码放在一个template 函数中,该函数可以针对所有 4 种不同类型进行实例化。然后,在所有 4 个分支中,调用此模板。编译器会生成 4 个不同的实例。

【讨论】:

    【解决方案2】:
    template<class F>
    arma::mat some_function(bool a, bool b, unsigned long int c, F f) {
      if(a) {
        if(b) {
          arma::sp_mat d(c, c);
          return f(d);
        }
        arma::SpMat<short> d(c, c);
        return f(d);
      }
      if(b) {
        arma::mat d(c, c, fill::zeros);
        return f(d);
      }
      arma::Mat<short> d(c, c, fill::zeros);
      return f(d);
    }
    
    arma::mat some_function(bool a, bool b, unsigned long int c){
      return some_function(a, b, c,
        [](auto&& d)->arma::mat{
          // Some other computations and a return statement
        }
      );
    }
    

    我相信这可以解决您的问题,但需要

    这里的样式称为“续传样式”;第一个模板创建变量d,然后将其传递给您传递给它的函数。然后它返回当它反过来接受d时它所返回的函数。

    底部 lambda 中的代码必须能够处理 d 是模板函数中可能存在的任何类型,因为它不知道 bool 值是什么。

    (如果知道布尔值,还有其他方法,但通常答案是“如果你知道,并且只有一些是有效的,为什么布尔值存在?)

    功能编写起来非常简单,如果您告诉它使用 (它们早期的 C++14 预标准版本),大多数 编译器都支持它。如果没有,您可以替换它:

        [](auto&& d)->arma::mat{
          // Some other computations and a return statement
        }
    

    struct some_helper {
      template<class M>
      arma::mat operator()(M&& m)const {
        // Some other computations and a return statement
      }
    };
    

    some_function之外,然后

    arma::mat some_function(bool a, bool b, unsigned long int c){
      return some_function(a, b, c,
        some_helper{}
      );
    }
    

    的情况下,如果需要访问a/b/c,请将[]改为[&amp;]

    的情况下,如果你需要访问a/b/c,把它们作为成员变量(或引用)添加到some_helper,并在some_helper的构造函数中初始化,然后从some_function.

    我使用的 功能是简洁的语法模板化 lambda,它是生成琐碎的 类的语法糖。 lambda 还有一些我们不关心的(零成本)功能。

    【讨论】:

    • 谢谢。很好的答案。这比我预期的要不直观。
    【解决方案3】:

    您需要在同一块中作为不同变量定义的“其余计算”。有使用不同类型的案例;我希望代码然后仅使用您显示的相同代码。显然,代码可以分开。您还展示了为同一类型调用不同构造函数的两种情况;后续代码一旦创建就可以使用相同的变量。

    但是由于你没有展示剩下的代码,我不知道:这四种情况有什么共同的处理吗?任何通用代码都可以进入子程序。

    arma::mat some_function(bool a, bool b, unsigned long int c) {
      if(a) {
        if(b) {
          arma::sp_mat d(c, c);
            // Some other computations and a return statement
        } else {
          arma::SpMat<short> d(c, c);
            // Some other computations and a return statement
        }
      } else {
        if(b) {
          arma::mat d(c, c, fill::zeros);
            // Some other computations and a return statement
        } else {
          arma::Mat<short> d(c, c, fill::zeros);
            // Some other computations and a return statement
        }
      }
    // no return here; unreachable.
    }
    

    “其他计算”每个都看到自己的变量。如果这四个分支之间有很多共同点,把它放在一个共同的子程序中,它们都可以调用。

    【讨论】:

      猜你喜欢
      • 2017-08-14
      • 2019-01-11
      • 1970-01-01
      • 2018-11-15
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 2012-05-30
      相关资源
      最近更新 更多