Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编写一个可以返回一个或多个值的函数_C++_Idioms - Fatal编程技术网

C++ 编写一个可以返回一个或多个值的函数

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,这里有一个解决方案,建议将可选指针传递到向量,并仅在存在时填充它。我删除了它,因为其他答案也提到了它,并且后一个解决方案看起来更优雅 您

假设我想写一个函数,比如说,返回某个范围内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,这里有一个解决方案,建议将可选指针传递到向量,并仅在存在时填充它。我删除了它,因为其他答案也提到了它,并且后一个解决方案看起来更优雅

您可以将计算抽象为迭代器,因此调用程序仍然非常简单,不会复制任何代码:

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