আপনাকে ফরওয়ার্ডিং সমস্যাটি বুঝতে হবে। আপনি পুরো সমস্যাটি বিশদে পড়তে পারেন , তবে আমি সংক্ষেপে বলব।
মূলত, এক্সপ্রেশন দেওয়া E(a, b, ... , c)
, আমরা অভিব্যক্তি f(a, b, ... , c)
সমমান হতে চান । C ++ 03 এ এটি অসম্ভব। অনেক চেষ্টা আছে, কিন্তু তারা সব কিছু ক্ষেত্রে ব্যর্থ হয়।
সবচেয়ে সহজ হল একটি ল্যাভেলু-রেফারেন্স ব্যবহার করা:
template <typename A, typename B, typename C>
void f(A& a, B& b, C& c)
{
E(a, b, c);
}
তবে এটি অস্থায়ী মানগুলি হ্যান্ডেল করতে ব্যর্থ হয়: f(1, 2, 3);
কারণ সেগুলি কোনও মূল্য-রেফারেন্সের সাথে আবদ্ধ হতে পারে না।
পরবর্তী প্রচেষ্টা হতে পারে:
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
E(a, b, c);
}
যা উপরের সমস্যাটি সমাধান করে তবে ফ্লপ ফ্লপ করে। এটি এখন E
অবিচ্ছিন্ন তর্ক করার অনুমতি দিতে ব্যর্থ :
int i = 1, j = 2, k = 3;
void E(int&, int&, int&); f(i, j, k); // oops! E cannot modify these
তৃতীয় প্রচেষ্টা const-রেফারেন্স গ্রহণ, কিন্তু তারপর const_cast
's const
দূরে:
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
E(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}
এটি সমস্ত মানকে স্বীকার করে, সমস্ত মানকে অতিক্রম করতে পারে, তবে সম্ভাব্যভাবে অনির্ধারিত আচরণের দিকে পরিচালিত করে:
const int i = 1, j = 2, k = 3;
E(int&, int&, int&); f(i, j, k); // ouch! E can modify a const object!
একটি চূড়ান্ত সমাধান সবকিছু সঠিকভাবে পরিচালনা করে ... রক্ষণাবেক্ষণ করা অসম্ভব হয়ে ওঠে। কনস্ট এবং নন-কনস্টের সমস্ত সংমিশ্রণ f
সহ আপনি ওভারলোডগুলি সরবরাহ করেন :
template <typename A, typename B, typename C>
void f(A& a, B& b, C& c);
template <typename A, typename B, typename C>
void f(const A& a, B& b, C& c);
template <typename A, typename B, typename C>
void f(A& a, const B& b, C& c);
template <typename A, typename B, typename C>
void f(A& a, B& b, const C& c);
template <typename A, typename B, typename C>
void f(const A& a, const B& b, C& c);
template <typename A, typename B, typename C>
void f(const A& a, B& b, const C& c);
template <typename A, typename B, typename C>
void f(A& a, const B& b, const C& c);
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c);
এন আর্গুমেন্টগুলিতে 2 এন সংমিশ্রণ প্রয়োজন, একটি দুঃস্বপ্ন। আমরা এটি স্বয়ংক্রিয়ভাবে করতে চাই।
(এটি কার্যকরভাবে আমরা সি ++ 11 এ আমাদের জন্য সংকলকটি পেতে পারি))
সি ++ 11 এ আমরা এটি ঠিক করার সুযোগ পাই। একটি সমাধান বিদ্যমান ধরণের উপর টেমপ্লেট ছাড়ের নিয়মগুলিকে সংশোধন করে, তবে এটি সম্ভাব্যভাবে কোডের একটি বিশাল চুক্তি ভঙ্গ করে। সুতরাং আমাদের আর একটি উপায় খুঁজে বের করতে হবে।
সমাধানটি পরিবর্তে সদ্য যুক্ত হওয়া মূল্য-রেফারেন্সগুলি ব্যবহার করা হয় ; মূল্য-রেফারেন্স প্রকারগুলি হ্রাস করার সময় আমরা নতুন বিধিগুলি প্রবর্তন করতে পারি এবং যে কোনও পছন্দসই ফলাফল তৈরি করতে পারি। সর্বোপরি, আমরা সম্ভবত এখন কোড ভাঙতে পারি না।
যদি কোনও রেফারেন্সকে একটি রেফারেন্স দেওয়া হয় (দ্রষ্টব্য রেফারেন্সটি উভয় T&
এবং এর অর্থ একটি অন্তর্ভুক্ত শব্দ T&&
), ফলাফলটি খুঁজে বের করার জন্য আমরা নিম্নলিখিত নিয়মটি ব্যবহার করি:
"[প্রদত্ত] একটি টাইপ টিআর যা টাইপ টি-এর একটি রেফারেন্স," সিভিআর টিআর-র লভ্যালু রেফারেন্স "টাইপ তৈরির প্রয়াস" টিতে লভ্যালু রেফারেন্স "টাইপ তৈরি করে, যখন টাইপটি" রেভ্যালু রেফারেন্স "টাইপ তৈরি করার চেষ্টা করে সিভি টিআর "টিআর টাইপ তৈরি করে।"
বা সারণী আকারে:
TR R
T& & -> T& // lvalue reference to cv TR -> lvalue reference to T
T& && -> T& // rvalue reference to cv TR -> TR (lvalue reference to T)
T&& & -> T& // lvalue reference to cv TR -> lvalue reference to T
T&& && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T)
এরপরে, টেমপ্লেট আর্গুমেন্ট ছাড়ের সাথে: যদি একটি আর্গুমেন্টটি লভ্যালু এ হয় তবে আমরা টেমপ্লেট যুক্তিটি এ এর একটি লভ্যালু রেফারেন্স সরবরাহ করি অন্যথায়, আমরা সাধারণত ছাড়াই। এটি তথাকথিত সর্বজনীন রেফারেন্স দেয় ( ফরোয়ার্ডিং রেফারেন্স শব্দটি এখন সরকারী one
কেন এটি দরকারী? সম্মিলিত হওয়ায় আমরা কোনও প্রকারের মান বিভাগের ট্র্যাক রাখার ক্ষমতা বজায় রাখি: এটি যদি একটি মূল্য ছিল তবে আমাদের মধ্যে একটি মূল্য-রেফারেন্স প্যারামিটার রয়েছে, অন্যথায় আমাদের একটি মান-রেফারেন্স প্যারামিটার রয়েছে।
কোডে:
template <typename T>
void deduce(T&& x);
int i;
deduce(i); // deduce<int&>(int& &&) -> deduce<int&>(int&)
deduce(1); // deduce<int>(int&&)
শেষ জিনিসটি ভেরিয়েবলের মান বিভাগ "ফরোয়ার্ড" করা। মনে রাখবেন, একবার ফাংশনের ভিতরে প্যারামিটারটি কোনও কিছুর মূল্য হিসাবে পাস হতে পারে:
void foo(int&);
template <typename T>
void deduce(T&& x)
{
foo(x); // fine, foo can refer to x
}
deduce(1); // okay, foo operates on x which has a value of 1
এটা কোন ভাল। E এর মতো ধরণের মান-বিভাগ হওয়া আমাদের দরকার! সমাধানটি হ'ল:
static_cast<T&&>(x);
এটি কি করে? বিবেচনা করুন আমরা deduce
ফাংশনটির ভিতরে রয়েছি, এবং আমাদের একটি লভালু পাস হয়েছে। এর অর্থ T
হ'ল একটি A&
, এবং তাই স্থির castালাইয়ের জন্য লক্ষ্য প্রকারটি A& &&
, বা ঠিক A&
। যেহেতু x
ইতিমধ্যে একটি A&
, তাই আমরা কিছুই করি না এবং একটি লভ্যালু রেফারেন্স রেখেই চলেছি।
যখন আমাদের কোনও মূল্য পাস হয়ে যায়, তখন T
হয় A
, সুতরাং স্থির কাস্টের জন্য লক্ষ্য প্রকারটি A&&
। কাস্টের ফলে একটি মূল্যবোধের অভিব্যক্তি হয়, যা আর কোনও মূল্যমানের রেফারেন্সে পাস করা যায় না । আমরা প্যারামিটারটির মান বিভাগটি বজায় রেখেছি।
এগুলি একসাথে রাখলে আমাদের "নিখুঁত ফরওয়ার্ডিং" পাওয়া যায়:
template <typename A>
void f(A&& a)
{
E(static_cast<A&&>(a));
}
যখন f
একটি কদর প্রাপ্ত হয় E
, একটি মূল্য পাওয়া যায়। যখন f
একটি মূল্যবোধ প্রাপ্ত হয় E
, একটি মূল্যায়ন পায়। পারফেক্ট।
এবং অবশ্যই আমরা কুরুচি থেকে মুক্তি পেতে চাই। static_cast<T&&>
মনে রাখা ক্রিপ্টিক এবং অদ্ভুত; এর পরিবর্তে একটি ইউটিলিটি ফাংশন তৈরি করা যাক forward
যা একই কাজ করে:
std::forward<A>(a);
// is the same as
static_cast<A&&>(a);
f
একটি ফাংশন হবে না , এবং একটি অভিব্যক্তি না?