সি ++ স্ট্যান্ডার্ড :: রেফ (টি) এবং টি ও এর মধ্যে পার্থক্য?


92

এই প্রোগ্রাম সম্পর্কে আমার কিছু প্রশ্ন রয়েছে:

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
    auto r=ref(x);
    cout<<boolalpha;
    cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
    int x=5;
    foo (x);
    return 0;
}

আউটপুটটি হ'ল:

false

আমি জানতে চাই, যদি std::refকোনও জিনিসের রেফারেন্স না ফেরায়, তবে এটি কী করে? মূলত, এর মধ্যে পার্থক্য কী:

T x;
auto r = ref(x);

এবং

T x;
T &y = x;

এছাড়াও, আমি জানতে চাই কেন এই পার্থক্যটি বিদ্যমান? আমাদের কেন প্রয়োজন std::refবা std::reference_wrapperযখন আমাদের রেফারেন্স রয়েছে (যেমন T&)?



ইঙ্গিত: যদি আপনি x = y; উভয় ক্ষেত্রেই করেন?
janchopanza

4
দেখুন উদাহরণস্বরূপ: আমার ডুপ্লিকেট পতাকা (শেষ মন্তব্য) ছাড়াও stackoverflow.com/questions/31270810/... এবং stackoverflow.com/questions/26766939/...
anderas

4
@ আন্ডারাস এটি দরকারীতার বিষয়ে নয়, এটি মূলত পার্থক্য সম্পর্কে
CppNITR

@CppNITR তারপরে আপনার মন্তব্যের কয়েক সেকেন্ড আগে আমি যে প্রশ্নগুলি যুক্ত করেছি সেগুলি দেখুন। বিশেষত দ্বিতীয়টি দরকারী।
anderas

উত্তর:


91

ভাল refকোনও বস্তুর reference_wrapperরেফারেন্স ধরে রাখতে উপযুক্ত টাইপের একটি অবজেক্ট তৈরি করে r আপনি যখন আবেদন করেন যার অর্থ:

auto r = ref(x);

এটি (যেমন ) এর reference_wrapperসরাসরি উল্লেখ হিসাবে নয় এবং প্রদান করে returns এটি (অর্থাত্ ) পরিবর্তে ধরে রাখে ।xT&reference_wrapperrT&

একটি reference_wrapperখুবই দরকারী যখন আপনি একটি অনুকরণ করতে চান referenceএকটি বস্তু যা কপি করা যেতে পারে (এটি উভয় কপি-অঙ্কনযোগ্য এবং কপি-হস্তান্তরযোগ্য )।

সি ++ এ, আপনি একবার yকোনও বস্তুর (বলুন x) রেফারেন্স তৈরি করুন (বলুন ), yএবং xএকই বেস ঠিকানাটি ভাগ করুন । তদ্ব্যতীত, yঅন্য কোনও বস্তুর উল্লেখ করতে পারে না। এছাড়াও আপনি রেফারেন্সের একটি অ্যারে তৈরি করতে পারবেন না, যেমন কোড এর ফলে একটি ত্রুটি ঘটবে:

#include <iostream>
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    int& arr[] {x,y,z};    // error: declaration of 'arr' as array of references
    return 0;
}

তবে এটি আইনী:

#include <iostream>
#include <functional>  // for reference_wrapper
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    reference_wrapper<int> arr[] {x,y,z};
    for (auto a: arr)
        cout << a << " ";
    return 0;
}
/* OUTPUT:
5 7 8
*/

আপনার সমস্যার সাথে কথা বলার cout << is_same<T&,decltype(r)>::value;সমাধানটি হ'ল:

cout << is_same<T&,decltype(r.get())>::value;  // will yield true

আমি আপনাকে একটি প্রোগ্রাম দেখাতে দিন:

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;

int main()
{
    cout << boolalpha;
    int x=5, y=7;
    reference_wrapper<int> r=x;   // or auto r = ref(x);
    cout << is_same<int&, decltype(r.get())>::value << "\n";
    cout << (&x==&r.get()) << "\n";
    r=y;
    cout << (&y==&r.get()) << "\n";
    r.get()=70;
    cout << y;
    return 0;
}
/* Ouput:
true
true
true
70
*/

এখানে দেখুন আমরা তিনটি জিনিস জানতে পারি:

  1. কোনও reference_wrapperঅবজেক্ট (এখানে r) রেফারেন্সের অ্যারে তৈরি করতে ব্যবহার করা যেতে পারে যা দিয়ে সম্ভব ছিল না T&

  2. rআসলে একটি বাস্তব রেফারেন্সের মতো কাজ করে (দেখুন কীভাবে r.get()=70এর মান পরিবর্তন হয়েছিল y)।

  3. rT&কিন্তু হিসাবে একই নয় r.get()। এর অর্থ rহ'ল T&অর্থাত্ হ'ল যেমন এর নামটিই বোঝায় একটি রেফারেন্সের চারপাশে একটি মোড়ক T&

আমি আশা করি এই উত্তরটি আপনার সন্দেহগুলি ব্যাখ্যা করার জন্য যথেষ্ট বেশি।


4
1: না, এটিকে পুনরায় নিয়োগ দেওয়াreference_wrapper যেতে পারে , তবে এটি "একাধিক বস্তুর রেফারেন্স ধরে রাখতে পারে না"। ২/৩: যেখানে উপযুক্ত সেখানে ন্যায্য পয়েন্ট - তবে অসম্পর্কিত ক্ষেত্রে একই রকম ব্যবহার করা যেতে পারে যেখানে রূপান্তরটি নির্বিঘ্নে আহ্বান করা যেতে পারে - তাই আপনার কোডের কয়েকটি সহ অনেক ক্ষেত্রে কল করার প্রয়োজন নেই (যা পড়া কঠিন) জায়গাগুলির অভাবে)। .get()r T&roperator.get()
আন্ডারস্কোর_১১

reference_wrapperআপনি যদি নিশ্চিত না হন তবে @sindor_d একটি রেফারেন্সের অ্যারে ধরে রাখতে পারে তবে আপনি নিজে চেষ্টা করে দেখতে পারেন। প্লাস .get()ব্যবহার করা হয় যখন আপনি যে বস্তুটি ধারণ করছেন তার মান পরিবর্তন করতে চান - reference_wrapperঅর্থাত r=70অবৈধ তাই আপনাকে ব্যবহার করতে হবে r.get()=70। নিজে চেষ্টা করুন !!!!!!
অঙ্কিত আচার্য

4
আসলে তা না. প্রথমে আসুন সঠিক শব্দটি ব্যবহার করা যাক। আপনি একটি অ্যারে রেফারেন্স ধারণ করে একটি রেফারেন্স_ওয়ালা দেখিয়ে চলেছেন - একটি রেফারেন্স_ওয়ালা যা নিজেই "একাধিক বস্তুর রেফারেন্স" ধারণ করে । মোড়ক কেবল একটি রেফারেন্স ধারণ করে। দ্বিতীয়ত, আমি ঠিক অ্যারেতে একটি নেটিভ রেফারেন্স পেতে পারি - আপনি কি নিশ্চিত যে আপনি চারপাশে (প্রথম বন্ধনী) ভুলে গেছেন না int a[4]{1, 2, 3, 4}; int (&b)[4] = a;? দেশীয় কাজ T& করে বলে এখানে রেফারেন্স_ওয়ালা বিশেষ নয় ।
আন্ডারস্কোর_১১

4
@AnkitAcharya হ্যাঁ :-) কিন্তু ভালো হবে, কার্যকর ফলাফলের সরাইয়া, নিজেই শুধুমাত্র এক বস্তু বোঝায়। যাইহোক, আপনি অবশ্যই ঠিক বলেছেন যে কোনও সাধারণ রেফের বিপরীতে, wrapperএকটি পাত্রে যেতে পারে। এটি সুবিধাজনক, তবে আমি মনে করি লোকেরা এটির চেয়ে বেশি উন্নত হিসাবে এটির ভুল ব্যাখ্যা করে। যদি আমি 'রেফস' এর একটি অ্যারে চাই, আমি সাধারণত মধ্যস্থতাকে এড়িয়ে যাই vector<Item *>, যা এটাই wrapperফোটায় ... এবং আশা করি বিরোধী-পয়েন্টার পিউরিস্টরা আমাকে খুঁজে পাবেন না। এর জন্য দৃinc়প্রত্যয়ী ব্যবহারের কেসগুলি আলাদা এবং আরও জটিল।
আন্ডারস্কোর_ডি

4
"যখন আপনি অনুলিপি করা যায় এমন কোনও সামগ্রীর রেফারেন্স অনুকরণ করতে চান তখন একটি রেফারেন্স_ওয়ালা খুব দরকারী" " কিন্তু তা কি রেফারেন্সের উদ্দেশ্যকে পরাভূত করে না? আপনি প্রকৃত জিনিস উল্লেখ করছেন। এটাই রেফারেন্স IS এমন একটি রেফারেন্স যা অনুলিপি করা যায়, অর্থহীন বলে মনে হয়, কারণ আপনি যদি এটি অনুলিপি করতে চান, তবে আপনি প্রথমে একটি রেফারেন্স চান না, আপনার কেবল আসল বস্তুটি অনুলিপি করা উচিত। জটিলতার একটি অপ্রয়োজনীয় স্তরের মতো মনে হচ্ছে এমন কোনও সমস্যা সমাধানের জন্য যা প্রথমে উপস্থিত থাকার প্রয়োজন নেই।
স্টু

53

std::reference_wrapper পাস-বাই-মান প্রসঙ্গে রেফারেন্স দ্বারা অবজেক্টগুলি পাস করতে সক্ষম হতে স্ট্যান্ডার্ড সুবিধাগুলি দ্বারা স্বীকৃত।

উদাহরণস্বরূপ, কিছুতে std::bindনিতে std::ref()পারে, এটি মান দ্বারা সঞ্চারিত করতে পারে এবং এটিকে পরে কোনও রেফারেন্সে আনপ্যাক করে।

void print(int i) {
    std::cout << i << '\n';
}

int main() {
    int i = 10;

    auto f1 = std::bind(print, i);
    auto f2 = std::bind(print, std::ref(i));

    i = 20;

    f1();
    f2();
}

এই স্নিপেট আউটপুট:

10
20

এটির সূচনা হওয়া পর্যায়ে এর iমান সংরক্ষণ করা হয়েছে ( মান অনুসারে নেওয়া) f1, তবে মান অনুসারে f2এটি রাখা হয়েছে std::reference_wrapperএবং এটি যেমনটি গ্রহণ করেছে তেমন আচরণ করে int&


4
নিশ্চিত করুন আমাকে একটি ছোট ডেমো একত্র করার জন্য একটি মুহুর্ত দিন :)
কোয়ান্টিন

4
টি অ্যান্ড অ্যান্ড রেফ (টি) এর মধ্যে পার্থক্য সম্পর্কে কী
CppNITR

4
@CppNITR std::ref(T)একটি ফেরৎ std::reference_wrapper। এটি মোড়ানো পয়েন্টারের চেয়ে কিছুটা বেশি, তবে গ্রন্থাগারটি "হেই, আমার একটি রেফারেন্স হওয়ার কথা!" হিসাবে পরিচিতি পেয়েছেন! একবার আপনি আমাকে পাস করার পরে আমাকে আবার ফিরিয়ে দিন "।
কোয়ান্টিন

38

একটি রেফারেন্স ( T&বা T&&) সি ++ ভাষার একটি বিশেষ উপাদান। এটি রেফারেন্সের মাধ্যমে কোনও বস্তু হেরফের করতে দেয় এবং ভাষায় বিশেষ ব্যবহারের ক্ষেত্রে রয়েছে। উদাহরণস্বরূপ, আপনি রেফারেন্সগুলি ধরে রাখতে কোনও আদর্শ ধারক তৈরি করতে পারবেন না: vector<T&>অসুস্থটি গঠিত এবং সংকলন ত্রুটি তৈরি করে।

একটি std::reference_wrapperঅন্যদিকে একটি সি ++ এর রেফারেন্স বহন করতে সক্ষম অবজেক্ট। যেমন, আপনি এটি স্ট্যান্ডার্ড পাত্রে ব্যবহার করতে পারেন।

std::refএটি একটি স্ট্যান্ডার্ড ফাংশন যা std::reference_wrapperতার তর্ককে ফিরিয়ে দেয় । একই ধারণাটিতে, কনস্টের রেফারেন্সে std::crefফিরে আসে std::reference_wrapper

ক এর একটি আকর্ষণীয় সম্পত্তি std::reference_wrapperহ'ল এটির একটি রয়েছে operator T& () const noexcept;। এর অর্থ হ'ল এটি যদি সত্য বস্তু হয় তবে এটি যে রেফারেন্সটি ধারণ করে তা স্বয়ংক্রিয়ভাবে রূপান্তরিত হতে পারে। সুতরাং:

  • যেহেতু এটি অনুলিপিযোগ্য অনুলিপি বিষয়বস্তু, এটি পাত্রে বা অন্যান্য ক্ষেত্রেও উল্লেখ করা যেতে পারে যেখানে ব্যবহারের অনুমতি নেই
  • এর জন্য ধন্যবাদ operator T& () const noexcept;, এটি আপনি যে কোনও রেফারেন্স ব্যবহার করতে পারে এমন কোনও জায়গায় ব্যবহার করা যেতে পারে, কারণ এটি স্বয়ংক্রিয়ভাবে এতে রূপান্তরিত হবে।

4
upvated মূলত কারণ operator T& ()অন্যান্য 2 উত্তর উল্লেখ করতে ব্যর্থ যা উল্লেখ।
মেটাব্লাস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.