C++ 编写一个可以返回一个或多个值的函数
假设我想写一个函数,比如说,返回某个范围内x的f(x)和C++ 编写一个可以返回一个或多个值的函数,c++,idioms,C++,Idioms,假设我想写一个函数,比如说,返回某个范围内x的f(x)和 double func() { double sum = 0.; for (int i=0; i<100; i++) { sum += f(i); } return sum; } double func(){ 双和=0。; 对于(int i=0;i,这里有一个解决方案,建议将可选指针传递到向量,并仅在存在时填充它。我删除了它,因为其他答案也提到了它,并且后一个解决方案看起来更优雅 您
double func() {
double sum = 0.;
for (int i=0; i<100; i++) {
sum += f(i);
}
return sum;
}
double func(){
双和=0。;
对于(int i=0;i,这里有一个解决方案,建议将可选指针传递到向量,并仅在存在时填充它。我删除了它,因为其他答案也提到了它,并且后一个解决方案看起来更优雅
您可以将计算抽象为迭代器,因此调用程序仍然非常简单,不会复制任何代码:
auto make_transform_counting_iterator(int i) {
return boost::make_transform_iterator(
boost::make_counting_iterator(i),
f);
}
auto my_begin() {
return make_transform_counting_iterator(0);
}
auto my_end() {
return make_transform_counting_iterator(100);
}
double only_sum() {
return std::accumulate(my_begin(), my_end(), 0.0);
}
std::vector<double> fill_terms() {
std::vector<double> result;
std::copy(my_begin(), my_end(), std::back_inserter(result));
return result;
}
auto make\u transform\u counting\u迭代器(inti){
return boost::make_transform_迭代器(
boost::make_counting_迭代器(i),
f) );
}
自动我的_开始(){
返回make_transform_counting_迭代器(0);
}
自动我的结束(){
返回make_transform_counting_迭代器(100);
}
仅双倍金额(){
返回std::累计(my_begin(),my_end(),0.0);
}
std::向量填充项(){
std::向量结果;
std::copy(my_begin()、my_end()、std::back_inserter(result));
返回结果;
}
一种简单的方法是编写一个公共函数,并使用输入参数执行条件。如下所示:
double logic(vector<double>* terms) {
double sum = 0.;
for (int i=0; i<100; i++) {
if (terms != NULL) {
terms.push_back(i);
}
sum += terms[i];
}
return sum;
}
double func() {
return logic(NULL);
}
pair<vector<double>,double> func_terms() {
vector<double> terms;
double sum = logic(&ret);
return {terms, sum};
}
双逻辑(向量*项){
双和=0。;
对于(int i=0;i如果您不支持:
std::pair<std::vector<double>, double> func_terms() {
std::vector<double> terms(100);
for (int i = 0; i != 100; ++i) {
terms[i] = f(i);
}
return {terms, std::accumulate(terms.begin(), terms.end(), 0.)};
}
std::pair func_terms(){
std::向量项(100);
对于(int i=0;i!=100;++i){
术语[i]=f(i);
}
返回{terms,std::accumulate(terms.begin(),terms.end(),0.);
}
那么也许:
template <typename Accumulator>
Accumulator& func_helper(Accumulator& acc) {
for (int i=0; i<100; i++) {
acc(f(i));
}
return acc;
}
double func()
{
double sum = 0;
func_helper([&sum](double d) { sum += d; });
return sum;
}
std::pair<std::vector<double>, double> func_terms() {
double sum = 0.;
std::vector<double> terms;
func_helper([&](double d) {
sum += d;
terms.push_back(d);
});
return {terms, sum};
}
模板
累加器和函数助手(累加器和附件){
对于(int i=0;i我制定了一个OOP解决方案,其中基类总是计算sum并使当前项可用于派生类,如下所示:
class Func
{
public:
Func() { sum = 0.; }
void func()
{
for (int i=0; i<100; i++)
{
double term = f(i);
sum += term;
useCurrentTerm(term);
}
}
double getSum() const { return sum; }
protected:
virtual void useCurrentTerm(double) {} //do nothing
private:
double f(double d){ return d * 42;}
double sum;
};
class函数
{
公众:
Func(){sum=0;}
void func()
{
对于(int i=0;i这种情况,我认为最简单的解决方案如下:
double f(int x) { return x * x; }
auto terms(int count) {
auto res = vector<double>{};
generate_n(back_inserter(res), count, [i=0]() mutable {return f(i++);});
return res;
}
auto func_terms(int count) {
const auto ts = terms(count);
return make_pair(ts, accumulate(begin(ts), end(ts), 0.0));
}
auto func(int count) {
return func_terms(count).second;
}
double f(int x){返回x*x;}
自动术语(整数计数){
自动恢复=向量{};
生成(返回插入器(res),计数,[i=0]()可变{returnf(i++);});
返回res;
}
自动函数项(整数计数){
const auto ts=术语(计数);
返回make_对(ts,累加(开始(ts),结束(ts),0.0));
}
自动函数(整数计数){
返回函数项(计数)。秒;
}
但这种方法给出了func()不同于原始版本的性能特性。在当前STL上有很多方法,但这突出了STL不适合组合性的一个区域。库提供了一种更好的方法来为这种类型的问题编写算法,并且正在为未来的C++版本标准化的过程中。
一般来说,组合性/重用性和最佳性能之间经常存在权衡。在最佳C++中,我们也可以有蛋糕,也可以吃,但这是一个例子,在这里我们正在进行一些工作,以提供标准的C++更好的方法来处理这种情况。“编写一个可以返回一个或多个值的函数”,但不仅仅如此;正如您的示例所示,在返回结果之前,函数还可能执行许多不同的操作。对于如此广泛的问题,确实没有通用的解决方案
但是,对于您所解释的特定情况,我想提供一个低技术的解决方案。您可以简单地根据第三个函数实现这两个函数,并为第三个函数提供一个参数,以确定是否执行额外的功能
下面是一个C++17示例,其中第三个函数被称为func_impl
,或多或少隐藏在一个名称空间中,以使func
和func_terms
的客户端更容易使用:
namespace detail {
enum class FuncOption {
WithTerms,
WithoutTerms
};
std::tuple<std::vector<double>, double> func_impl(FuncOption option) {
auto const withTerms = option == FuncOption::WithTerms;
double sum = 0.;
std::vector<double> terms(withTerms ? 100 : 0);
for (int i = 0; i < 100; ++i) {
auto const result = f(i);
if (withTerms) {
terms[i] = result;
}
sum += result;
}
return std::make_tuple(terms, sum);
}
}
double func() {
using namespace detail;
return std::get<double>(func_impl(FuncOption::WithTerms));
}
std::tuple<std::vector<double>, double> func_terms() {
using namespace detail;
return func_impl(FuncOption::WithoutTerms);
}
名称空间详细信息{
枚举类函数选项{
有条件的,
无条件
};
std::tuple func_impl(FuncOption){
自动常量withTerms=option==FuncOption::withTerms;
双和=0。;
std::矢量项(术语?100:0);
对于(int i=0;i<100;++i){
自动常数结果=f(i);
如有(附带条款){
术语[i]=结果;
}
总和+=结果;
}
return std::make_tuple(术语、总和);
}
}
双func(){
使用名称空间细节;
返回std::get(func_impl(FuncOption::WithTerms));
}
std::tuple func_terms(){
使用名称空间细节;
返回func_impl(FuncOption::WithoutTerms);
}
这是不是太低的技术取决于你的确切问题。
你可以使用<代码>可选的<代码>,它可以在Boost和AFAK中使用,最新的C++版本之一也可以摆脱<代码>和>代码>然后<代码>返回{术语,STD::Stand(术语:开始),术语“()(0)))
?@Jarod42,这仍然需要两个函数:一个返回{terms,std::acculate…},另一个返回{std::acculate…}当代码比一个std::acculate调用更复杂时,它并没有解决代码重复的问题,而这正是OP所建议的。您能否详细说明您在实现double func(){return func_terms().second;}时在实践中观察到的性能差异
?优化器实际上可能比您预期的要好。这个想法并不坏,解决方案看起来比我自己的更干净,但是关于代码的一些细节很奇怪:构造函数中没有初始化列表,没有getSum
的const
,冗余受保护的其中私有的就足够了,没有std::
在可能位于头文件中的代码中。我认为您对const和std的看法是正确的,谢谢,我编辑了代码。这是非常老式的代码;自从C++11引入nullptr
以来,不仅应该不再使用NULL
,而且从C++17开始使用std::optional
时,使用指针是不好的(和boost::optional
或一些自制的可选CLA
class FuncWithTerms : public Func
{
public:
FuncWithTerms() { terms.reserve(100); }
std::vector<double> getTerms() const { return terms; }
protected:
void useCurrentTerm(double t) { terms.push_back(t); }
private:
std::vector<double> terms;
};
double sum_only_func()
{
Func f;
f.func();
return f.getSum();
}
std::pair<std::vector<double>, double> with_terms_func()
{
FuncWithTerms fwt;
fwt.func();
return { fwt.getTerms(), fwt.getSum() };
}
double f(int x) { return x * x; }
auto terms(int count) {
auto res = vector<double>{};
generate_n(back_inserter(res), count, [i=0]() mutable {return f(i++);});
return res;
}
auto func_terms(int count) {
const auto ts = terms(count);
return make_pair(ts, accumulate(begin(ts), end(ts), 0.0));
}
auto func(int count) {
return func_terms(count).second;
}
namespace detail {
enum class FuncOption {
WithTerms,
WithoutTerms
};
std::tuple<std::vector<double>, double> func_impl(FuncOption option) {
auto const withTerms = option == FuncOption::WithTerms;
double sum = 0.;
std::vector<double> terms(withTerms ? 100 : 0);
for (int i = 0; i < 100; ++i) {
auto const result = f(i);
if (withTerms) {
terms[i] = result;
}
sum += result;
}
return std::make_tuple(terms, sum);
}
}
double func() {
using namespace detail;
return std::get<double>(func_impl(FuncOption::WithTerms));
}
std::tuple<std::vector<double>, double> func_terms() {
using namespace detail;
return func_impl(FuncOption::WithoutTerms);
}