Ada banyak cara untuk mengembalikan beberapa parameter. Saya akan sangat bersemangat.
Gunakan parameter referensi:
void foo( int& result, int& other_result );
gunakan parameter pointer:
void foo( int* result, int* other_result );
yang memiliki keuntungan yang harus Anda lakukan &
di situs panggilan, mungkin memperingatkan orang itu adalah parameter di luar.
Tulis templat dan gunakan:
template<class T>
struct out {
std::function<void(T)> target;
out(T* t):target([t](T&& in){ if (t) *t = std::move(in); }) {}
out(std::optional<T>* t):target([t](T&& in){ if (t) t->emplace(std::move(in)); }) {}
out(std::aligned_storage_t<sizeof(T), alignof(T)>* t):
target([t](T&& in){ ::new( (void*)t ) T(std::move(in)); } ) {}
template<class...Args> // TODO: SFINAE enable_if test
void emplace(Args&&...args) {
target( T(std::forward<Args>(args)...) );
}
template<class X> // TODO: SFINAE enable_if test
void operator=(X&&x){ emplace(std::forward<X>(x)); }
template<class...Args> // TODO: SFINAE enable_if test
void operator()(Args...&&args){ emplace(std::forward<Args>(args)...); }
};
maka kita bisa melakukan:
void foo( out<int> result, out<int> other_result )
dan semuanya baik-baik saja. foo
tidak lagi dapat membaca nilai apa pun yang diteruskan sebagai bonus.
Cara lain untuk mendefinisikan tempat Anda dapat memasukkan data dapat digunakan untuk membangun out
. Callback untuk membereskan hal-hal di suatu tempat, misalnya.
Kami dapat mengembalikan struktur:
struct foo_r { int result; int other_result; };
foo_r foo();
whick berfungsi ok di setiap versi C ++, dan di c ++ 17 ini juga memungkinkan:
auto&&[result, other_result]=foo();
dengan biaya nol. Parameter bahkan tidak bisa dipindahkan berkat jaminan pemilihan.
Kami dapat mengembalikan std::tuple
:
std::tuple<int, int> foo();
yang memiliki kelemahan yang parameternya tidak disebutkan. Ini memungkinkanc ++ 17:
auto&&[result, other_result]=foo();
demikian juga. Sebelumc ++ 17 sebaliknya kita bisa melakukan:
int result, other_result;
std::tie(result, other_result) = foo();
yang hanya sedikit lebih canggung. Namun, penjaminan yang dijamin tidak berfungsi di sini.
Pergi ke wilayah orang asing (dan ini setelah out<>
!), Kita dapat menggunakan gaya passing lanjutan:
void foo( std::function<void(int result, int other_result)> );
dan sekarang penelepon melakukan:
foo( [&](int result, int other_result) {
/* code */
} );
manfaat dari gaya ini adalah Anda dapat mengembalikan sejumlah nilai arbitrer (dengan tipe seragam) tanpa harus mengelola memori:
void get_all_values( std::function<void(int)> value )
yang value
callback bisa disebut ketika 500 kali Anda get_all_values( [&](int value){} )
.
Untuk kegilaan murni, Anda bahkan bisa menggunakan kelanjutan pada kelanjutan.
void foo( std::function<void(int, std::function<void(int)>)> result );
yang penggunaannya terlihat seperti:
foo( [&](int result, auto&& other){ other([&](int other){
/* code */
}) });
yang akan memungkinkan banyak-satu hubungan antara result
dan other
.
Sekali lagi dengan nilai uniforn, kita dapat melakukan ini:
void foo( std::function< void(span<int>) > results )
di sini, kami memanggil panggilan balik dengan rentang hasil. Kami bahkan dapat melakukan ini berulang kali.
Menggunakan ini, Anda dapat memiliki fungsi yang secara efisien melewati megabita data tanpa melakukan alokasi apa pun dari tumpukan.
void foo( std::function< void(span<int>) > results ) {
int local_buffer[1024];
std::size_t used = 0;
auto send_data=[&]{
if (!used) return;
results({ local_buffer, used });
used = 0;
};
auto add_datum=[&](int x){
local_buffer[used] = x;
++used;
if (used == 1024) send_data();
};
auto add_data=[&](gsl::span<int const> xs) {
for (auto x:xs) add_datum(x);
};
for (int i = 0; i < 7+(1<<20); ++i) {
add_datum(i);
}
send_data(); // any leftover
}
Sekarang, std::function
agak berat untuk ini, karena kita akan melakukan ini di lingkungan tanpa alokasi nol-overhead. Jadi kami ingin function_view
yang tidak pernah mengalokasikan.
Solusi lain adalah:
std::function<void(std::function<void(int result, int other_result)>)> foo(int input);
di mana alih-alih menerima panggilan balik dan menjalankannya, foo
alih-alih mengembalikan fungsi yang menerima panggilan balik.
foo (7) ([&] (hasil int, int other_result) {/ * kode * /}); ini memecah parameter output dari parameter input dengan memiliki tanda kurung terpisah.
Dengan variant
danc ++ 20coroutine, Anda bisa membuat foo
generator dari varian tipe kembali (atau hanya tipe kembali). Sintaksnya belum diperbaiki, jadi saya tidak akan memberikan contoh.
Dalam dunia sinyal dan slot, fungsi yang memaparkan serangkaian sinyal:
template<class...Args>
struct broadcaster;
broadcaster<int, int> foo();
memungkinkan Anda untuk membuat foo
async yang berfungsi dan menyiarkan hasilnya ketika sudah selesai.
Di bawah garis ini kami memiliki berbagai teknik pipa, di mana suatu fungsi tidak melakukan sesuatu melainkan mengatur agar data dihubungkan dengan cara tertentu, dan tindakannya relatif independen.
foo( int_source )( int_dest1, int_dest2 );
maka kode ini tidak melakukan apa pun sampai int_source
memiliki bilangan bulat untuk menyediakannya. Ketika itu terjadi, int_dest1
dan int_dest2
mulai menerima hasilnya.