简体   繁体   English

C++11 条件数据类型

[英]C++11 conditional data type

I wrote a C++11 function that conditionally initializes an object.我写了一个 C++11 function 有条件地初始化一个 object。 Consider the following example:考虑以下示例:

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
}

As you can see, I want to initialize an object d where the (Armadillo) data type depends on booleans a and b .如您所见,我想初始化一个 object d ,其中(犰狳)数据类型取决于布尔值ab Unfortunately, it does not compile, with the compiler complaining about d not being declared in the scope where it is subsequently used.不幸的是,它无法编译,编译器抱怨d没有在随后使用的 scope 中声明。

I found various discussions on similar issues.我发现了关于类似问题的各种讨论。 Conditional initialization is apparently introduced in C++17. C++17 中显然引入了条件初始化。 However, I need to use C++11 in this application.但是,我需要在此应用程序中使用 C++11。 Other suggestions mention the type_traits library and lambda functions.其他建议提到type_traits库和 lambda 函数。 And many discussions focus on conditionally specifying the object's content rather than its data type.许多讨论集中在有条件地指定对象的内容而不是其数据类型。 As I am still fairly new to C++, I am not sure how to apply any of these options to the this nested conditional structure.由于我对 C++ 还很陌生,我不确定如何将这些选项中的任何一个应用于这个嵌套的条件结构。

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
    }
  );
}

I believe this solves your problem, but requires .我相信这可以解决您的问题,但需要

The style here is called "continuation passing style";这里的风格称为“续传风格”; the first template creates the variable d , then passes that to a function you passed to it.第一个模板创建变量d ,然后将其传递给您传递给它的 function 。 It then returns what the function it takes returns when it in turn takes a d .然后它返回它返回的 function 当它反过来接收d时返回的内容。

The code within the lambda at the bottom must be able to handle d being any of the types it could be within the template function, because it doesn't know what the bool values will be.底部 lambda 中的代码必须能够处理d作为模板 function 中可能存在的任何类型,因为它不知道布尔值是什么。

(If the bool values are known there are other approaches, but often the answer is "if you know that, and only some are valid, why do the bools exist?) (如果知道布尔值,还有其他方法,但通常答案是“如果你知道,并且只有一些是有效的,为什么布尔值存在?)

The feature was so simple to write most compilers support it if you tell it to use (their early pre-standard version of C++14). 功能非常简单,如果您告诉它使用 (他们早期的 C++14 预标准版本),大多数编译器都支持它。 If not, you can just replace this:如果没有,您可以替换它:

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

with

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

outside of some_function , thensome_function之外,然后

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

In the case, if you need access to a/b/c, change [] to [&] .情况下,如果需要访问 a/b/c,请将[]更改为[&]

In the case, if you need access to a/b/c, add them to some_helper as member variables (or references) and initialize them in some_helper 's constructor, and pass them in from some_function .案例中,如果您需要访问 a/b/c,请将它们作为成员变量(或引用)添加到some_helper并在some_helper的构造函数中对其进行初始化,然后从some_function传递它们。

The feature I'm using is the terse syntax templated lambda, which is syntactic sugar to generate the trivial class. The feature I'm using is the terse syntax templated lambda, which is syntactic sugar to generate the trivial class. The lambda has a few more (zero cost) features we don't care about. lambda 还有一些我们不关心的(零成本)功能。

You'll probably need to put the common code in a template function which can be instantiated for all 4 different types.您可能需要将通用代码放入template function 中,该模板可以针对所有 4 种不同类型进行实例化。 Then, in all 4 branches, call this template.然后,在所有 4 个分支中,调用此模板。 The compiler will generate 4 different instantiations.编译器将生成 4 个不同的实例。

You need "the rest of the computations" in the same block as the different variable definitions.您需要在与不同变量定义相同的块中“计算的 rest”。 There are cases that use different types;有使用不同类型的案例; I expect that the code then uses only the same one you showed being defined.我希望代码然后仅使用您显示的定义的相同代码。 Clearly that code can be separate.显然,代码可以分开。 You also showed two cases where different constructors are called for the same type;您还展示了为同一类型调用不同构造函数的两种情况; subsequent code can use the same variable, once it had been created.一旦创建,后续代码可以使用相同的变量。

But since you didn't show the rest of the code, I don't know: is there any common processing among the four cases?但是由于你没有显示代码的rest,不知道:这四种情况有什么共同处理吗? Any common code can go into subroutines.任何通用代码都可以 go 变成子程序。

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.
}

The "other computations" each see their own variable. “其他计算”每个都看到自己的变量。 If there is a lot of commonality among those four branches, put it in a common subroutine that they can all call.如果这四个分支之间有很多共同点,就把它放在一个它们都可以调用的公共子程序中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM