ল্যাম্বদা ক্যাপচার এবং একই নামের প্যারামিটার - কে অন্যটিকে ছায়া দেয়? (ঝনঝন বনাম জিসিসি)


125
auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
  • ঝাঁকুনি ++ 3.6.0 এবং আরও নতুন প্রিন্ট আউট "আপনি ঝাঁকুনি ব্যবহার করছেন ++!" এবং ক্যাপচারটি foo অব্যবহৃত হওয়ার বিষয়ে সতর্ক করুন ।

  • g ++ 4.9.0 এবং আরও নতুন প্রিন্ট আউট "আপনি জি ++ ব্যবহার করছেন!" এবং প্যারামিটারটি foo অব্যবহৃত হওয়ার বিষয়ে সতর্ক করুন ।

এখানে আরও কত নির্ভুলভাবে সি ++ স্ট্যান্ডার্ড অনুসরণ করছে কোন সংকলক?

ভ্যান্ডবক্স উদাহরণ


1
কোডটি এখানে ভ্যান্ডবক্স থেকে আটকানো (তারা ভাগ করে নেওয়ার বোতামটি ভুলে গেছে বলে মনে হচ্ছে) দেখে মনে হচ্ছে যেন ভিএস ২০১৫ (?) ঝাঁকুনির সাথে একমত পোষণ করে C4458: 'ফু' ঘোষণা শ্রেণীর সদস্যকে গোপন করে
nwp

12
দুর্দান্ত উদাহরণ ..
deviantfan

4
ল্যামডা একটি টেমপ্লেট ফাংশন কল অপারেটর সঙ্গে একটি টাইপ আছে, এইভাবে যুক্তিবিজ্ঞান আমাকে বলে যে প্যারামিটার হিসাবে যদি বন্দী পরিবর্তনশীল ছায়া উচিত হবে struct Lambda { template<typename T> void operator()(T foo) const { /* ... */ } private: decltype(outer_foo) foo{outer_foo}; }
skypjack

2
@ এনডব্লিউ ভিএস ভুল, ল্যাম্বডায় ডেটা সদস্যরা নামহীন এবং এইভাবে ছায়া দেওয়া যায় না। স্ট্যান্ডার্ডটি বলেছে যে "একটি বন্দী সত্তা অ্যাক্সেসের সাথে সম্পর্কিত ডেটা সদস্যের অ্যাক্সেসে রূপান্তরিত হয়", যা আমাদের বর্গাকারে ছেড়ে যায়।
এন। 'সর্বনাম' মি।

10
আমি আশা করব যে ঝাঁকুনির সংস্করণটি সঠিক হয়েছে - এটি কোনও ফাংশনটির বাইরের কিছু যদি চারপাশের অন্য উপায়ে পরিবর্তে ফাংশন প্যারামিটারের ছায়া দেয় তবে এটি নতুন স্থলটি ভঙ্গ করবে!
এমএম

উত্তর:


65

আপডেট: নীচের উদ্ধৃতিতে কোর চেয়ারের প্রতিশ্রুতি অনুসারে, কোডটি এখন দূষিত :

একটি এমন শনাক্তকারী একটি সহজ-ক্যাপচার হিসাবে প্রদর্শিত হবে declarator-আইডি একটি পরামিতির ল্যামডা-declarator এর প্যারামিটার-ঘোষণা-দফা , প্রোগ্রাম মন্দ গঠিত হয়।


কিছুক্ষণ আগে ল্যাম্বডাসে নাম অনুসন্ধান সম্পর্কিত কয়েকটি সমস্যা ছিল। তারা N2927 দ্বারা সমাধান করা হয়েছিল :

নতুন শব্দবন্ধ আর ধরা পড়া সত্তাগুলির পুনর্নির্মাণের জন্য লুকের উপর নির্ভর করে না। এটি আরও স্পষ্টভাবে ব্যাখ্যাগুলি অস্বীকার করে যে একটি ল্যাম্বার যৌগিক বিবৃতি দুটি পাসে প্রক্রিয়াজাত করা হয় বা যে যৌগিক-বিবৃতিতে কোনও নাম বন্ধের ধরণের কোনও সদস্যকে সমাধান করতে পারে।

ল্যাম্পডা-এক্সপ্রেশন প্রসঙ্গে লুপআপ সর্বদা করা হয় , কোনও ক্লোজার টাইপের সদস্য ফাংশন বডিতে রূপান্তর "পরে" কখনই হয় না। দেখুন [expr.prim.lambda] / 8 :

ল্যামডা প্রকাশ এর যৌগ-বিবৃতি উৎপাদ ফাংশন শরীরের ফাংশন কল অপারেটর ([dcl.fct.def]), কিন্তু এখনও পর্যন্ত নাম লুকআপ উদ্দেশ্য পূরণকল্পে, [...], যৌগ-বিবৃতি প্রসঙ্গে বিবেচনা করা হয় ল্যামডা প্রকাশ । [ উদাহরণ :

struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x+y);  // equivalent to: S1::operator()(this->x+(*this).y)
                                     // and this has type S1*
    }; 
  }
};

- শেষ উদাহরণ ]

(উদাহরণটি এও স্পষ্ট করে তোলে যে লুকোচুরি কোনওভাবে বন্ধের ধরণের উত্পন্ন ক্যাপচার সদস্যকে বিবেচনা করে না))

নাম fooক্যাপচারে ঘোষণা করা হয়নি (পুনরায়); এটি ল্যাম্বডা এক্সপ্রেশনটি সংযুক্ত করে ব্লকে ঘোষণা করা হয়। প্যারামিটারটি fooএমন একটি ব্লকে ঘোষিত হয় যা বাইরের ব্লকে বাসা বাঁধে (দেখুন [বেসিক.স্কোপ.ব্লক] / 2 দেখুন , যা স্পষ্টভাবে ল্যাম্বডা পরামিতিগুলিও উল্লেখ করে)। অভ্যন্তরীণ থেকে বাইরের ব্লকগুলিতে দেখার ক্রমটি স্পষ্ট । সুতরাং প্যারামিটারটি নির্বাচন করা উচিত, অর্থাত্ কলঙ্কটি সঠিক।

আপনি যদি ক্যাপচারটি একটি আরম্ভ-ক্যাপচার foo = ""হিসাবে করেন foo, তার পরিবর্তে , উত্তরটি পরিষ্কার হবে না। এর কারণ হ'ল ক্যাপচারটি আসলে একটি ঘোষণাকে প্ররোচিত করে যার "ব্লক" দেওয়া হয়নি। আমি এই বিষয়ে মূল চেয়ার বার্তা দিয়েছি, কে জবাব দিয়েছে

এটি 2211 ইস্যু (খুব শীঘ্রই একটি নতুন ইস্যু তালিকা ওপেন -স্ট.ডি.আর.আর্টোগুলি সাইটে উপস্থিত হবে, দুর্ভাগ্যক্রমে বেশ কয়েকটি সমস্যার জন্য কেবল স্থানধারীদের সাথে, যার মধ্যে এটি একটি; আমি এই ফাঁকগুলি পূরণ করার জন্য কঠোর পরিশ্রম করছি মাস শেষে সভা)। সিডব্লুজি আমাদের জানুয়ারির টেলিকনফারেন্সের সময় এটি নিয়ে আলোচনা করেছিল এবং ক্যাপচারের নামটিও যদি প্যারামিটারের নাম হয় তবে প্রোগ্রামটি দুর্নীতিগ্রস্থ করার দিকনির্দেশনা।


আমাকে পৃথক্ এখানে চেরা জন্য কিছুই :) একটি সহজ-ক্যাপচার , কিছুই ঘোষণা তাই নাম লুকআপ সঠিক ফলাফলের মোটামুটি সুস্পষ্ট (BTW, জিসিসি এটি পায় ডান আপনি একটি ব্যবহার ক্যাপচার-ডিফল্ট স্পষ্ট ক্যাপচার পরিবর্তে)। আরআই-ক্যাপচার গুলি কিছুটা জটিল।
টিসি

1
@ টিসি আমি সম্মত আমি একটি মূল সমস্যা দায়ের করেছি, তবে দৃশ্যত এটি ইতিমধ্যে আলোচনা করা হয়েছে, সম্পাদিত উত্তরটি দেখুন।
কলম্বো

6

আমি আপনাকে অর্থপূর্ণ উত্তর দেওয়ার জন্য প্রশ্নের কয়েকটি মন্তব্য একসাথে প্যাক করার চেষ্টা করছি।
প্রথমত, দ্রষ্টব্য:

  • প্রতিটি অনুলিপি-ক্যাপচারেড ভেরিয়েবলের জন্য ল্যাম্বদার জন্য অ স্থিতিশীল ডেটা সদস্য ঘোষণা করা হয়
  • নির্দিষ্ট ক্ষেত্রে, ল্যাম্বডায় একটি ক্লোজার টাইপ রয়েছে যাতে একটি সার্বজনীন ইনলাইন টেম্পলেট ফাংশন কল অপারেটর নামের একটি প্যারামিটার গ্রহণ করে foo

সুতরাং যুক্তিটি আমাকে প্রথম নজরে বলতে বাধ্য করবে যে প্যারামিটারটি ক্যাপচারড ভেরিয়েবলের ছায়া উচিত in

struct Lambda {
    template<typename T> void operator()(T foo) const { /* ... */ }
    private: decltype(outer_foo) foo{outer_foo};
};

যাইহোক, @nm সঠিকভাবে উল্লেখ করেছে যে অনুলিপি তথ্য অনুলিপি কপি-ক্যাপচার ভেরিয়েবল জন্য ঘোষিত আসলে নামবিহীন। বলা হচ্ছে, নামবিহীন ডেটা সদস্য এখনও সনাক্তকারী (যা foo) এর মাধ্যমে অ্যাক্সেস করা যায় । সুতরাং, ফাংশন কল অপারেটরের প্যারামিটারের নামটি এখনও শনাক্ত করা উচিত (আমাকে বলতে দিন) যা শনাক্তকারী
প্রশ্নের উত্তরগুলিতে @ এনএম দ্বারা সঠিকভাবে নির্দেশিত:

মূল বন্দী সত্তা [...] স্কোপ নিয়ম অনুসারে সাধারণত ছায়া করা উচিত

তার কারণেই, আমি বলতে পারি যে ঝাঁকুনি ঠিক আছে।


উপরে বর্ণিত হিসাবে, এই প্রসঙ্গে অনুসন্ধানটি কখনই করা হয় না যেমন আমরা রূপান্তরিত বন্ধের ধরণে থাকি।
কলম্বো

@ কলম্বো আমি একটি লাইন যুক্ত করছি যা আমি যুক্তি থেকে পরিষ্কার থাকলেও আমি মিস করেছি, এটি হ'ল ঝাঁকুনি ঠিক। মজার অংশটি হ'ল আমি উত্তর দেওয়ার চেষ্টা করার সময় [expr.prim.lambda] / 8 পেয়েছি তবে আপনি যেমনটি করেছেন তেমনভাবে আমি এটি সঠিকভাবে ব্যবহার করতে পারিনি। এজন্য প্রতিবার আপনার উত্তরগুলি পড়ে আনন্দিত। ;-)
স্কাইপজ্যাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.