প্রথমত, "এটির জন্য রেফ-কোয়ালিফায়ার" এটি একটি "বিপণন বিবৃতি"। *this
কখনই পরিবর্তন হয় না, এই পোস্টের নীচে দেখুন। যদিও এই শব্দটির সাহায্যে এটি বোঝার সহজ উপায়।
এর পরে, নিম্নলিখিত কোড বেছে ফাংশন উপর ভিত্তি করে বলা হবে ; ref-কোয়ালিফায়ার ফাংশনের "অন্তর্নিহিত বস্তুর পরামিতি" এর † :
// t.cpp
#include <iostream>
struct test{
void f() &{ std::cout << "lvalue object\n"; }
void f() &&{ std::cout << "rvalue object\n"; }
};
int main(){
test t;
t.f(); // lvalue
test().f(); // rvalue
}
আউটপুট:
$ clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic t.cpp
$ ./a.out
lvalue object
rvalue object
পুরো জিনিসটি যখন আপনাকে ফাংশনটি কল করা হয় সেই বস্তুটি একটি মূল্য (যখন নামবিহীন অস্থায়ী, উদাহরণস্বরূপ) হয় তখন আপনাকে সেই সত্যের সুবিধা নিতে দেয় allow নিম্নলিখিত কোডটিকে আরও উদাহরণ হিসাবে ধরুন:
struct test2{
std::unique_ptr<int[]> heavy_resource;
test2()
: heavy_resource(new int[500]) {}
operator std::unique_ptr<int[]>() const&{
// lvalue object, deep copy
std::unique_ptr<int[]> p(new int[500]);
for(int i=0; i < 500; ++i)
p[i] = heavy_resource[i];
return p;
}
operator std::unique_ptr<int[]>() &&{
// rvalue object
// we are garbage anyways, just move resource
return std::move(heavy_resource);
}
};
এটি কিছুটা স্বীকৃত হতে পারে তবে আপনার ধারণাটি নেওয়া উচিত।
মনে রাখবেন আপনি সিভি-বাছাইকারী ( const
এবং volatile
) এবং রেফ-কোয়ালিফায়ার ( &
এবং &&
) একত্রিত করতে পারেন ।
দ্রষ্টব্য: এখানে অনেক স্ট্যান্ডার্ড কোট এবং ওভারলোড রেজোলিউশন ব্যাখ্যা!
This এটি কীভাবে কাজ করে তা বুঝতে, এবং কেন @ নিকোল বোলাসের উত্তর অন্তত আংশিক ভুল, আমাদের কিছুটা জন্য সি ++ স্ট্যান্ডার্ডটি খনন করতে হবে (@ নিকোলের উত্তর কেন ভুল তা ব্যাখ্যা করার অংশটি নীচে রয়েছে, আপনি যদি কেবল এতে আগ্রহী)।
কোন ক্রিয়াকলাপটি বলা হবে তা ওভারলোড রেজোলিউশন নামে পরিচিত একটি প্রক্রিয়া দ্বারা নির্ধারিত হয় । এই প্রক্রিয়াটি মোটামুটি জটিল, সুতরাং আমরা কেবল আমাদের কাছে গুরুত্বপূর্ণ যেটিকে স্পর্শ করব।
প্রথমত, সদস্য ফাংশনগুলির জন্য ওভারলোড রেজোলিউশন কীভাবে কাজ করে তা দেখতে গুরুত্বপূর্ণ:
§13.3.1 [over.match.funcs]
p2 প্রার্থী ফাংশনগুলির সেটটিতে একই আর্গুমেন্ট তালিকার বিপরীতে সমাধান করতে সদস্য এবং অ-সদস্য উভয় ফাংশন থাকতে পারে। সুতরাং যে যুক্তি এবং পরামিতি তালিকাগুলি এই ভিন্ন ভিন্ন সেট মধ্যে তুলনাযোগ্য, একটি সদস্য ফাংশন একটি অতিরিক্ত পরামিতি বলে মনে করা হয়, যা অন্তর্ভুক্ত অবজেক্ট প্যারামিটার বলা হয়, যা বস্তুর প্রতিনিধিত্ব করে যার জন্য সদস্য ফাংশন বলা হয়েছে । [...]
p3 একইভাবে, যখন উপযুক্ত হয়, প্রসঙ্গটি আর্গুমেন্টের তালিকাটি তৈরি করতে পারে যাতে অবজেক্টটি চালিত হতে বোঝাতে কোনও অন্তর্নিহিত অবজেক্ট আর্গুমেন্ট থাকে।
আমাদের এমনকি সদস্য ও অ-সদস্যের কার্যকারিতা তুলনা করা কেন প্রয়োজন? অপারেটর ওভারলোডিং, এজন্যই। এই বিবেচনা:
struct foo{
foo& operator<<(void*); // implementation unimportant
};
foo& operator<<(foo&, char const*); // implementation unimportant
আপনি নীচেরগুলি অবশ্যই ফ্রি ফাংশনটি কল করতে চান, তাই না?
char const* s = "free foo!\n";
foo f;
f << s;
এই কারণেই সদস্য এবং অ-সদস্য ফাংশনগুলিকে তথাকথিত ওভারলোড-সেটটিতে অন্তর্ভুক্ত করা হয়েছে। রেজোলিউশনটিকে আরও জটিল করার জন্য, স্ট্যান্ডার্ড উদ্ধৃতিটির সাহসী অংশ বিদ্যমান। অতিরিক্তভাবে, এটি আমাদের জন্য গুরুত্বপূর্ণ বিট (একই ধারা):
পি 4 অ স্থিতিশীল সদস্য ফাংশনের জন্য, অন্তর্নিহিত বস্তুর প্যারামিটারের ধরণ
X
ফাংশনটি কোন শ্রেণীর সদস্য এবং সিভি হল সদস্য ফাংশন ঘোষণায় সিভি-যোগ্যতা where [...]
p5 ওভারলোড রেজোলিউশন চলাকালীন [...] [টি] তিনি আপত্তিজনক পরামিতি [...] সম্পর্কিত পরিচয়টি ধরে রাখছেন কারণ সম্পর্কিত যুক্তিতে রূপান্তরগুলি এই অতিরিক্ত নিয়ম মানবে:
অন্তর্নিহিত অবজেক্ট প্যারামিটারের জন্য আর্গুমেন্ট ধরে রাখতে কোনও অস্থায়ী বস্তু চালু করা যায় না; এবং
কোনও ব্যবহারকারীর দ্বারা সংজ্ঞায়িত রূপান্তরগুলি এর সাথে কোনও প্রকারের মিলটি অর্জন করতে প্রয়োগ করা যাবে না
[...]
(শেষ বিটের ঠিক অর্থ হ'ল আপনি সদস্য ফাংশন (বা অপারেটর) নামক বস্তুর অন্তর্নিহিত রূপান্তরগুলির ভিত্তিতে ওভারলোড রেজোলিউশনকে প্রতারণা করতে পারবেন না))
আসুন এই পোস্টের শীর্ষে প্রথম উদাহরণটি নেওয়া যাক। পূর্বোক্ত পরিবর্তিত রূপান্তরের পরে, ওভারলোড-সেটটি এরকম কিছু দেখাচ্ছে:
void f1(test&); // will only match lvalues, linked to 'void test::f() &'
void f2(test&&); // will only match rvalues, linked to 'void test::f() &&'
তারপরে একটি অন্তর্নিহিত বস্তুর যুক্তি যুক্ত যুক্তি তালিকাটি ওভারলোড-সেটে থাকা প্রতিটি ফাংশনের প্যারামিটার-তালিকার বিপরীতে মিলছে। আমাদের ক্ষেত্রে, যুক্তি তালিকায় কেবল সেই বস্তুর যুক্তিই থাকবে। দেখা যাক কেমন দেখাচ্ছে:
// first call to 'f' in 'main'
test t;
f1(t); // 't' (lvalue) can match 'test&' (lvalue reference)
// kept in overload-set
f2(t); // 't' not an rvalue, can't match 'test&&' (rvalue reference)
// taken out of overload-set
যদি, সেটের সমস্ত ওভারলোডগুলি পরীক্ষা করার পরে, শুধুমাত্র একটি অবশেষ থাকে, ওভারলোড রেজোলিউশন সফল হয় এবং সেই রূপান্তরিত ওভারলোডের সাথে যুক্ত ফাংশনটি বলা হয়। দ্বিতীয় কলটি 'চ' তে একইভাবে যায়:
// second call to 'f' in 'main'
f1(test()); // 'test()' not an lvalue, can't match 'test&' (lvalue reference)
// taken out of overload-set
f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference)
// kept in overload-set
তবে খেয়াল করুন যে, আমরা যদি কোনও রেফ-কোয়ালিফায়ার (এবং যেমন ফাংশনটি ওভারলোড না করে) সরবরাহ না করতাম, তবে এটি কোনও ফলাফলের f1
সাথে মেলে (এখনও §13.3.1
):
পি 5 [...] রেফ-কোয়ালিফায়ার ছাড়াই ঘোষিত অ স্থিতিশীল সদস্য ফাংশনের জন্য একটি অতিরিক্ত নিয়ম প্রযোজ্য:
- এমনকি যদি অন্তর্নিহিত অবজেক্ট প্যারামিটারকে
const
যোগ্যতা নাও দেওয়া হয়, তবুও একটি মূল্যায়ন প্যারামিটারের সাথে আবদ্ধ হতে পারে যতক্ষণ না অন্য সমস্ত ক্ষেত্রে যুক্তিটি অন্তর্নিহিত অবজেক্ট প্যারামিটারের ধরণে রূপান্তর করা যায়।
struct test{
void f() { std::cout << "lvalue or rvalue object\n"; }
};
int main(){
test t;
t.f(); // OK
test().f(); // OK too
}
এখন, কেন নিকোলের উত্তর অন্ততপক্ষে ভুল। তিনি বলেন:
দ্রষ্টব্য যে এই ঘোষণাটি এর ধরণের পরিবর্তন করে *this
।
যে ভুল, *this
হয় সবসময় একটি lvalue:
§5.3.1 [expr.unary.op] p1
ইউনারী *
অপারেটর সঞ্চালিত অপ্রত্যক্ষ্যতার : অভিব্যক্তি যা তা প্রয়োগ করা একটি বস্তু টাইপ একটি পয়েন্টার, অথবা একটি ফাংশন টাইপ একটি পয়েন্টার হইবে এবং ফলাফল একটি lvalue হয় বস্তু বা ফাংশন যা অভিব্যক্তি পয়েন্ট উল্লেখ।
§9.3.2 [class.this] p1
অ-স্থিতিশীল (9.3) সদস্য ফাংশনের this
মূল শব্দের মধ্যে কীওয়ার্ডটি একটি মূল্যবান প্রকাশ হয় যার মূল্যটি সেই বস্তুর ঠিকানা যেখানে ফাংশন বলা হয়। ধরণ this
একটি বর্গ সদস্য ফাংশনে X
হয় X*
। [...]