একাধিক প্যারামিটারগুলি ফেরত দেওয়ার অনেকগুলি উপায় রয়েছে। আমি উদাসীন হতে চলেছি।
রেফারেন্স পরামিতি ব্যবহার করুন:
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();
wh + সি ++ এর প্রতিটি সংস্করণে এবং ঠিক আছে 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 ফলাফল, অন্যান্য অন্যান্য ফলাফল) {/ * কোড * /}); এটি পৃথক বন্ধনী রেখে ইনপুট পরামিতিগুলি থেকে আউটপুট প্যারামিটারগুলি ভেঙে দেয়।
সাথে variant
এবংC ++ 20কর্টাইনগুলি, আপনি foo
রিটার্নের ধরণের (বা কেবলমাত্র রিটার্নের ধরণের) বৈকল্পিকের একটি জেনারেটর তৈরি করতে পারেন। বাক্য গঠনটি এখনও ঠিক হয়নি, তাই আমি উদাহরণ দেব না।
সংকেত এবং স্লট জগতে, একটি ফাংশন যা সংকেতগুলির একটি সেট প্রকাশ করে:
template<class...Args>
struct broadcaster;
broadcaster<int, int> foo();
আপনাকে এমন একটি তৈরি করতে দেয় foo
যা অ্যাসিঙ্ক কাজ করে এবং ফলাফলটি শেষ হওয়ার পরে এটি সম্প্রচার করে।
এই লাইনের নীচে আমাদের কাছে পাইপলাইনের বিভিন্ন কৌশল রয়েছে, যেখানে কোনও ফাংশন কিছু না করে বরং কোনও উপায়ে ডেটা সংযুক্ত হওয়ার ব্যবস্থা করে, এবং করা অপেক্ষাকৃত স্বতন্ত্র।
foo( int_source )( int_dest1, int_dest2 );
তারপর এই কোড না কি কিছু না হওয়া পর্যন্ত int_source
এটা প্রদান পূর্ণসংখ্যার হয়েছে। এটি যখন হয়ে যায় int_dest1
এবং int_dest2
ফলাফলগুলি পাওয়া শুরু করুন start