มีหลายวิธีในการส่งคืนพารามิเตอร์หลายรายการ ฉันจะตื่นเต้น
ใช้พารามิเตอร์อ้างอิง:
void foo( int& result, int& other_result );
ใช้พารามิเตอร์ตัวชี้:
void foo( int* result, int* other_result );
ซึ่งมีข้อได้เปรียบที่คุณต้องทำ&
ที่ไซต์การโทรอาจเป็นการแจ้งเตือนบุคคลว่าเป็นพารามิเตอร์ที่ไม่เหมาะสม
เขียนเทมเพลตและใช้งาน:
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)...); }
};
จากนั้นเราสามารถทำได้:
void foo( out<int> result, out<int> other_result )
และทุกอย่างก็ดี foo
ไม่สามารถอ่านค่าใด ๆ ที่ส่งผ่านเป็นโบนัสได้อีกต่อไป
วิธีการอื่น ๆ out
ของการกำหนดจุดที่คุณสามารถใส่ข้อมูลที่สามารถนำมาใช้ในการสร้าง เช่นการโทรกลับเพื่อวางบางสิ่งบางอย่างเช่น
เราสามารถคืนโครงสร้าง:
struct foo_r { int result; int other_result; };
foo_r foo();
whick ทำงานได้ดีในทุกรุ่นของ C ++ และใน C ++ 17 สิ่งนี้ยังอนุญาตให้:
auto&&[result, other_result]=foo();
ที่ศูนย์ค่าใช้จ่าย แม้จะไม่สามารถเคลื่อนย้ายพารามิเตอร์ได้ด้วยการรับประกันการรับประกัน
เราสามารถส่งคืนstd::tuple
:
std::tuple<int, int> foo();
ซึ่งมีข้อเสียที่พารามิเตอร์ไม่ได้ตั้งชื่อ สิ่งนี้อนุญาตให้C ++ 17:
auto&&[result, other_result]=foo();
เช่นกัน ก่อนหน้าC ++ 17 เราสามารถทำได้:
int result, other_result;
std::tie(result, other_result) = foo();
ซึ่งน่าอึดอัดใจนิดหน่อย อย่างไรก็ตามการรับประกันแบบไม่ทำงานที่นี่
ไปสู่ดินแดนคนแปลกหน้า (และนี่คือหลังจากout<>
!) เราสามารถใช้รูปแบบการส่งต่อ:
void foo( std::function<void(int result, int other_result)> );
และตอนนี้ผู้โทรทำ:
foo( [&](int result, int other_result) {
/* code */
} );
ประโยชน์ของสไตล์นี้คือคุณสามารถคืนค่าตามอำเภอใจได้ (โดยมีรูปแบบเหมือนกัน) โดยไม่ต้องจัดการหน่วยความจำ:
void get_all_values( std::function<void(int)> value )
value
โทรกลับอาจจะเรียกว่า 500 get_all_values( [&](int value){} )
ครั้งเมื่อคุณ
เพื่อความวิกลจริตอย่างบริสุทธิ์คุณสามารถใช้ความต่อเนื่องในการสานต่อ
void foo( std::function<void(int, std::function<void(int)>)> result );
การใช้งานดูเหมือนว่า:
foo( [&](int result, auto&& other){ other([&](int other){
/* code */
}) });
ซึ่งจะอนุญาตให้หลายหนึ่งความสัมพันธ์ระหว่างและresult
other
อีกครั้งด้วยค่ายูนิคอร์นเราสามารถทำสิ่งนี้:
void foo( std::function< void(span<int>) > results )
ที่นี่เราเรียกการเรียกกลับด้วยผลลัพธ์เป็นระยะ ๆ เราสามารถทำสิ่งนี้ซ้ำ ๆ ได้
การใช้สิ่งนี้คุณสามารถมีฟังก์ชั่นที่ส่งผ่านข้อมูลได้อย่างมีประสิทธิภาพเมกะไบต์โดยไม่ต้องทำการจัดสรรใด ๆ ออกจากสแต็ก
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
}
ตอนนี้std::function
ค่อนข้างหนักสำหรับเรื่องนี้เพราะเราจะทำสิ่งนี้ในสภาพแวดล้อมที่ไม่มีการจัดสรรศูนย์ เราอยากได้สิ่งfunction_view
ที่ไม่เคยจัดสรร
ทางออกอื่นคือ:
std::function<void(std::function<void(int result, int other_result)>)> foo(int input);
โดยที่แทนที่จะใช้การติดต่อกลับและเรียกใช้งานfoo
แทนที่จะส่งกลับฟังก์ชันที่ใช้โทรกลับ
foo (7) ([&] (ผลลัพธ์ int, int other_result) {/ * code * /}); สิ่งนี้จะทำลายพารามิเตอร์เอาต์พุตจากพารามิเตอร์อินพุตโดยมีเครื่องหมายวงเล็บแยกกัน
ด้วยvariant
และC ++ 20coroutines คุณสามารถสร้างfoo
ตัวสร้างตัวแปรของชนิดส่งคืน (หรือเพียงแค่ชนิดส่งคืน) ไวยากรณ์ยังไม่ได้รับการแก้ไขดังนั้นฉันจะไม่ให้ตัวอย่าง
ในโลกของสัญญาณและช่องเสียบฟังก์ชันที่แสดงชุดสัญญาณ:
template<class...Args>
struct broadcaster;
broadcaster<int, int> foo();
ช่วยให้คุณสร้างfoo
ที่ทำงาน async และถ่ายทอดผลเมื่อเสร็จแล้ว
ในบรรทัดนี้เรามีเทคนิคไปป์ไลน์ที่หลากหลายที่ฟังก์ชั่นไม่ได้ทำอะไร แต่จัดเรียงข้อมูลที่จะเชื่อมต่อในบางวิธีและการทำนั้นค่อนข้างอิสระ
foo( int_source )( int_dest1, int_dest2 );
จากนั้นโค้ดนี้จะไม่ทำอะไรเลยจนกว่าจะint_source
มีจำนวนเต็มที่ระบุ เมื่อไหร่int_dest1
และint_dest2
เริ่มได้รับผลลัพธ์