问题描述
我写了一个 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,fill::zeros);
}
}
// Some other computations and a return statement
}
如您所见,我想初始化一个对象 d
,其中(Armadillo)数据类型取决于布尔值 a
和 b
。不幸的是,它没有编译,编译器抱怨 d
没有在它随后使用的作用域中声明。
我发现了关于类似问题的各种讨论。条件初始化显然是在 C++17 中引入的。但是,我需要在此应用程序中使用 C++11。其他建议提到了 type_traits
库和 lambda 函数。许多讨论集中在有条件地指定对象的内容而不是它的数据类型。由于我对 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,fill::zeros);
return f(d);
}
arma::mat some_function(bool a,unsigned long int c){
return some_function(a,b,[](auto&& d)->arma::mat{
// Some other computations and a return statement
}
);
}
我相信这可以解决您的问题,但需要 c++14。
这里的风格叫做“持续传递风格”;第一个模板创建变量 d
,然后将其传递给您传递给它的函数。然后它返回它所采用的函数在它又采用 d
时返回的内容。
底部 lambda 中的代码必须能够处理 d
是它可能在模板函数中的任何类型,因为它不知道 bool 值是什么。
(如果知道 bool 值,还有其他方法,但通常答案是“如果您知道,并且只有一些有效,为什么会存在 bool?)
c++14 功能非常简单,大多数 c++11 编译器都支持它,如果您告诉它使用 c++1y(它们的 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,some_helper{}
);
}
在 c++14 的情况下,如果您需要访问 a/b/c,请将 []
更改为 [&]
。
在c++11的情况下,如果需要访问a/b/c,将它们作为成员变量(或引用)添加到some_helper
中,并在some_helper
的构造函数中初始化,并从 some_function
传入。
我使用的 c++14 功能是简洁的语法模板化 lambda,它是生成简单 c++11 类的语法糖。 c++14 lambda 还有一些我们不关心的(零成本)特性。
,您可能需要将通用代码放在 template
函数中,该函数可以针对所有 4 种不同类型进行实例化。然后,在所有 4 个分支中,调用此模板。编译器将生成 4 个不同的实例。
您需要与不同变量定义在同一块中的“其余计算”。有使用不同类型的案例;我希望代码然后只使用您显示的定义的相同代码。显然,该代码可以分开。您还展示了为同一类型调用不同构造函数的两种情况;一旦创建了相同的变量,后续代码就可以使用相同的变量。
但是由于你没有展示其余的代码,我不知道:这四种情况之间有什么共同的处理吗?任何公共代码都可以进入子程序。
arma::mat some_function(bool a,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,fill::zeros);
// Some other computations and a return statement
} else {
arma::Mat<short> d(c,fill::zeros);
// Some other computations and a return statement
}
}
// no return here; unreachable.
}
“其他计算”每个都看到自己的变量。如果这四个分支之间有很多共同点,就放在一个他们都可以调用的公共子程序中。