避免为非默认参数创建临时变量?
Avoid creating temporary vars for params which are not defaulted?
这听起来可能是个疯狂的问题。
在我的 C++ 代码中,我创建了一个这样的方法
void Func(int & param_1, bool & param_2, float & param_3, double & param_4) {
//some logic
}
所以我调用了 main
中的方法,如下所示:
int i_val;
bool b_val;
float f_val;
double d_val;
//invoke Func here
Func(i_val, b_val, f_val, d_val);
问题:有什么方法可以避免创建临时变量i_val, b_val, f_val
等等?并在调用本身的行中创建它们?
我只对创建 i_val
和 b_val
并获取它们的值感兴趣。 f_val
和 d_val
对我来说是不必要的,但在其他与我无关的调用中是必需的。有没有办法避免创建临时变量只是为了将每个参数传递给调用?
我知道我们可以将最后 2 个参数设置为默认参数 但是使用默认参数会使调用者忽略函数参数。有没有办法不将最后 2 个参数设置为默认值?在调用方法的那一刻动态创建 float 和 double 变量
我知道我会收到关于为什么你不想使用默认参数的交叉问题,只是检查是否有可能:)
C++ 经验法则:
强制执行时的参考
当您将某些内容设为可选时的指针。当然,该函数中的代码需要考虑可以传递的 nullptr。
成功
void Func(int* pParam_1, bool* pParam_2, float* pParam_3, double* pParam_4) {
// some logic
}
当您有 四个 输出参数时,就像您在此处所做的那样:
void Func(int & param_1, bool & param_2, float & param_3, double & param_4);
这表明您真的想要 return 一个具有 4 个成员的对象,例如:
std::tuple<int, bool, float, double> Func();
或:
struct X {
int some;
bool meaningful;
float names;
double here;
};
X Func();
这样,你可以写:
auto res = Func();
然后只使用您想要的字段。
在 C++17 中,对于结构化绑定,可以是:
auto [ival, bval, _1, _2] = Func();
虽然没有明确的方式来表达您不关心第 3 名和第 4 名成员的想法,但这还不错。
对于像您这样的非const
参考,不。您可以考虑函数重载,返回包含这些值的 struct
,甚至从 C++11 开始返回 std::tuple
。 (请注意,std::tuple
在 C++14 中得到了重大升级。)
如果您引用 const
* 并依赖于结果的返回值,事情会变得更好。然后您可以将 anonymous temporaries 传递给调用站点的函数:
/*something*/ Func(const int& param_1, const bool& param_2, /*etc*/) {
}
并调用 Func(1, true)
等。使用 const
引用,您甚至可以提供默认值:
/*something*/ Func(const int& param_1 = 1, const bool& params_2 = true, /*etc*/){
* 一些编译器允许 绑定 匿名临时到非 const
引用作为扩展/无意的错误.但如果我是你,我不会依赖它。
你可以,但你必须知道虚拟临时对象会在完整表达式结束时消失:
template <typename T>
T& stay(T&& x = T()) {
return x;
}
void Func(int& param_1, bool& param_2, float& param_3, double& param_4) {
//some logic
}
int main() {
int arg_1; float arg_3;
Func(arg_1, stay<bool>(), arg_3, stay(42.0));
}
stay
将右值转换为左值,因此与 std::move
相反。
sort of create the float and double variables on the fly at the moment of invoking the method
为此,请使用您想要的值创建一个匿名临时文件。然后对其进行转换,以便您可以绑定到左值引用。
template<class T>
T& as_lvalue(T&& t={}){return t;}
void Func(int& param_1, bool& param_2, float& param_3, double& param_4) {
}
int main() {
int a1;
float a3;
Func(a1, as_lvalue(false), a3, as_lvalue(3.14));
}
as_lvalue
获取一个右值(或左值!)并将其转换为相同类型的左值。然后它可以绑定到左值引用,并在表达式末尾被丢弃。
如果您不关心它们的价值,您甚至可以这样做:
int main() {
int a1;
float a3;
Func(a1, as_lvalue<bool>(), a3, as_lvalue<double>());
}
请注意,使用参考参数作为纯输出参数有点代码味道。使用时,引用参数应该是in-out参数;他们进出的价值应该有用。
同时传入和传出数据的参数也很危险,因为它更难推断函数的行为。
一种非常干净的方法是采用 return 结构。
struct FuncArgs {
int param_1;
bool param_2;
float param_3;
double param_4;
};
FuncArgs Func(FuncArgs) {
//some logic
}
人们可以这样称呼它:
Func({3, true, 42.f, 3.14})
并像这样获取 return 数据:
auto r = Func({3, true, 42.f, 3.14})
int param1 = r.param1;
bool param2 = r.param2;
忽略 returned param3
和 param4
。
在 C++17 中,他们甚至可以做到:
auto[param1, param2, donotcare, alsodonotcare] = Func({3, true, 42.f, 3.14});
遗憾的是,无法完全跳过 donotcare
和 alsodonotcare
字段。
但是,如果您的数据是纯粹的结果,我们将删除 FuncArgs
个参数。
现在,修改每个调用 Func
的位置可能很烦人;但是感谢重载的奇迹,我们可以写:
inline FuncArgs Func() {
FuncArgs args;
Func(args.param1, args.param2, args.param3, args.param4);
return args;
}
或
inline FuncArgs Func(FuncArgs args) {
Func(args.param1, args.param2, args.param3, args.param4);
return args;
}
两人幸福地生活在一起。无需修改现有代码;新代码是。
这听起来可能是个疯狂的问题。
在我的 C++ 代码中,我创建了一个这样的方法
void Func(int & param_1, bool & param_2, float & param_3, double & param_4) {
//some logic
}
所以我调用了 main
中的方法,如下所示:
int i_val;
bool b_val;
float f_val;
double d_val;
//invoke Func here
Func(i_val, b_val, f_val, d_val);
问题:有什么方法可以避免创建临时变量i_val, b_val, f_val
等等?并在调用本身的行中创建它们?
我只对创建 i_val
和 b_val
并获取它们的值感兴趣。 f_val
和 d_val
对我来说是不必要的,但在其他与我无关的调用中是必需的。有没有办法避免创建临时变量只是为了将每个参数传递给调用?
我知道我们可以将最后 2 个参数设置为默认参数 但是使用默认参数会使调用者忽略函数参数。有没有办法不将最后 2 个参数设置为默认值?在调用方法的那一刻动态创建 float 和 double 变量
我知道我会收到关于为什么你不想使用默认参数的交叉问题,只是检查是否有可能:)
C++ 经验法则: 强制执行时的参考 当您将某些内容设为可选时的指针。当然,该函数中的代码需要考虑可以传递的 nullptr。
成功
void Func(int* pParam_1, bool* pParam_2, float* pParam_3, double* pParam_4) {
// some logic
}
当您有 四个 输出参数时,就像您在此处所做的那样:
void Func(int & param_1, bool & param_2, float & param_3, double & param_4);
这表明您真的想要 return 一个具有 4 个成员的对象,例如:
std::tuple<int, bool, float, double> Func();
或:
struct X {
int some;
bool meaningful;
float names;
double here;
};
X Func();
这样,你可以写:
auto res = Func();
然后只使用您想要的字段。
在 C++17 中,对于结构化绑定,可以是:
auto [ival, bval, _1, _2] = Func();
虽然没有明确的方式来表达您不关心第 3 名和第 4 名成员的想法,但这还不错。
对于像您这样的非const
参考,不。您可以考虑函数重载,返回包含这些值的 struct
,甚至从 C++11 开始返回 std::tuple
。 (请注意,std::tuple
在 C++14 中得到了重大升级。)
如果您引用 const
* 并依赖于结果的返回值,事情会变得更好。然后您可以将 anonymous temporaries 传递给调用站点的函数:
/*something*/ Func(const int& param_1, const bool& param_2, /*etc*/) {
}
并调用 Func(1, true)
等。使用 const
引用,您甚至可以提供默认值:
/*something*/ Func(const int& param_1 = 1, const bool& params_2 = true, /*etc*/){
* 一些编译器允许 绑定 匿名临时到非 const
引用作为扩展/无意的错误.但如果我是你,我不会依赖它。
你可以,但你必须知道虚拟临时对象会在完整表达式结束时消失:
template <typename T>
T& stay(T&& x = T()) {
return x;
}
void Func(int& param_1, bool& param_2, float& param_3, double& param_4) {
//some logic
}
int main() {
int arg_1; float arg_3;
Func(arg_1, stay<bool>(), arg_3, stay(42.0));
}
stay
将右值转换为左值,因此与 std::move
相反。
sort of create the float and double variables on the fly at the moment of invoking the method
为此,请使用您想要的值创建一个匿名临时文件。然后对其进行转换,以便您可以绑定到左值引用。
template<class T>
T& as_lvalue(T&& t={}){return t;}
void Func(int& param_1, bool& param_2, float& param_3, double& param_4) {
}
int main() {
int a1;
float a3;
Func(a1, as_lvalue(false), a3, as_lvalue(3.14));
}
as_lvalue
获取一个右值(或左值!)并将其转换为相同类型的左值。然后它可以绑定到左值引用,并在表达式末尾被丢弃。
如果您不关心它们的价值,您甚至可以这样做:
int main() {
int a1;
float a3;
Func(a1, as_lvalue<bool>(), a3, as_lvalue<double>());
}
请注意,使用参考参数作为纯输出参数有点代码味道。使用时,引用参数应该是in-out参数;他们进出的价值应该有用。
同时传入和传出数据的参数也很危险,因为它更难推断函数的行为。
一种非常干净的方法是采用 return 结构。
struct FuncArgs {
int param_1;
bool param_2;
float param_3;
double param_4;
};
FuncArgs Func(FuncArgs) {
//some logic
}
人们可以这样称呼它:
Func({3, true, 42.f, 3.14})
并像这样获取 return 数据:
auto r = Func({3, true, 42.f, 3.14})
int param1 = r.param1;
bool param2 = r.param2;
忽略 returned param3
和 param4
。
在 C++17 中,他们甚至可以做到:
auto[param1, param2, donotcare, alsodonotcare] = Func({3, true, 42.f, 3.14});
遗憾的是,无法完全跳过 donotcare
和 alsodonotcare
字段。
但是,如果您的数据是纯粹的结果,我们将删除 FuncArgs
个参数。
现在,修改每个调用 Func
的位置可能很烦人;但是感谢重载的奇迹,我们可以写:
inline FuncArgs Func() {
FuncArgs args;
Func(args.param1, args.param2, args.param3, args.param4);
return args;
}
或
inline FuncArgs Func(FuncArgs args) {
Func(args.param1, args.param2, args.param3, args.param4);
return args;
}
两人幸福地生活在一起。无需修改现有代码;新代码是。