从c++函数中返回多个值的首选方法是什么?例如,假设有一个函数对两个整数进行除法并同时返回商和余数。我经常看到的一种方法是使用引用形参:

void divide(int dividend, int divisor, int& quotient, int& remainder);

一种变体是返回一个值,并通过引用形参传递另一个值:

int divide(int dividend, int divisor, int& remainder);

另一种方法是声明一个结构体来包含所有的结果并返回:

struct divide_result {
    int quotient;
    int remainder;
};

divide_result divide(int dividend, int divisor);

这些方法中是否有一种通常是首选的,还是有其他的建议?

编辑:在实际代码中,可能会有两个以上的结果。它们也可能是不同类型的。


当前回答

这完全取决于实际函数和多个值的含义,以及它们的大小:

如果它们像分数的例子一样相关,那么我会使用结构体或类实例。 如果它们不是真正相关的,并且不能被分组到一个类/结构中,那么也许你应该将你的方法重构为两个。 根据所返回值在内存中的大小,您可能希望返回指向类实例或结构的指针,或者使用引用形参。

其他回答

c++ 17,使用std::make_tuple,结构化绑定和尽可能多的auto:

#include <tuple>

#include <string>
#include <cstring>

auto func() {
    // ...
    return std::make_tuple(1, 2.2, std::string("str"), "cstr");
}

int main() {
    auto [i, f, s, cs] = func();
    return i + f + s.length() + strlen(cs);
}

使用-O1完全优化:https://godbolt.org/z/133rT9Pcq -O3只需要优化std::string: https://godbolt.org/z/Mqbez73Kf

在这里:https://godbolt.org/z/WWKvE3osv,您可以看到GCC将所有返回值打包在一个内存块中(rdi+N), pod样式,证明没有性能损失。

在这里,我正在编写一个程序,在c++中返回多个值(超过两个值)。此程序在c++14 (g++ 4.9.2)中可执行。程序就像计算器。

#  include <tuple>
# include <iostream>

using namespace std; 

tuple < int,int,int,int,int >   cal(int n1, int n2)
{
    return  make_tuple(n1/n2,n1%n2,n1+n2,n1-n2,n1*n2);
}

int main()
{
    int qut,rer,add,sub,mul,a,b;
    cin>>a>>b;
    tie(qut,rer,add,sub,mul)=cal(a,b);
    cout << "quotient= "<<qut<<endl;
    cout << "remainder= "<<rer<<endl;
    cout << "addition= "<<add<<endl;
    cout << "subtraction= "<<sub<<endl;
    cout << "multiplication= "<<mul<<endl;
    return 0;
}

因此,您可以清楚地理解,通过这种方式,您可以从一个函数返回多个值。使用std::pair只能返回2个值,而std::tuple可以返回两个以上的值。

这里是关于这个主题的“核心指南”(由Bjarne Stroustrup和Herb Sutter撰写)的链接。

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-out-multi

部分报价:

F.21:要返回多个“out”值,最好返回一个结构体或元组 原因返回值是作为“仅输出”值自记录的。注意,根据使用元组(包括pair)的惯例,c++确实有多个返回值,可能在调用点使用额外方便的tie或结构化绑定(c++ 17)。首选使用有返回值语义的命名结构。否则,无名元组在泛型代码中很有用。

替代方案包括数组、生成器和控制反转,但在这里不适用。

有些(例如微软在历史上的Win32)倾向于使用引用参数来简化,因为它很清楚由谁分配以及它在堆栈上的外观,减少了结构的扩散,并允许成功的单独返回值。

“纯”程序员更喜欢结构体,假设它是函数值(就像这里的情况一样),而不是函数偶然接触的东西。如果您有一个更复杂的过程,或者带有状态的东西,您可能会使用引用(假设您有不使用类的理由)。

在c++ 17中,你还可以返回一个或多个不可移动/不可复制的值(在某些情况下)。通过新的有保证的返回值优化,可以返回不可移动的类型,并且可以很好地与聚合和模板化构造函数组合在一起。

template<typename T1,typename T2,typename T3>
struct many {
  T1 a;
  T2 b;
  T3 c;
};

// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;

auto f(){ return many{string(),5.7, unmovable()}; }; 

int main(){
   // in place construct x,y,z with a string, 5.7 and unmovable.
   auto [x,y,z] = f();
}

这样做的好处是,它保证不会引起任何复制或移动。你也可以让这个例子有很多可变结构。更多的细节:

返回c++ 17可变变量模板“构造推导指南”的可变变量聚合(struct)和语法