টাইপ করা তথ্য কখন সি ++ এ পিছনে প্রবাহিত হয়?


92

আমি সবেমাত্র CppCon 2018"ক্লাস টেম্পলেট আর্গুমেন্ট কমানো " তে স্টিফান টি। লাভভেজের আলাপ দেখেছি , যেখানে কোনও এক সময় তিনি ঘটনাচক্রে বলেছেন:

সি ++ ধরণের তথ্য প্রায় কখনই পিছনের দিকে প্রবাহিত হয় না ... আমাকে "প্রায়" বলতে হয়েছিল কারণ একটি বা দুটি ক্ষেত্রে সম্ভবত আরও বেশি তবে খুব কম রয়েছে

তিনি কোন কোন মামলার বিষয়ে উল্লেখ করছেন তা জানার চেষ্টা করেও আমি কিছুই নিয়ে আসতে পারিনি। সুতরাং প্রশ্ন:

কোন ক্ষেত্রে সি ++ 17 স্ট্যান্ডার্ড ম্যান্ডেটের ধরণের তথ্য পিছনের দিকে প্রচার করে?


আংশিক বিশেষীকরণ এবং ধ্বংসাত্মক কার্যাদি মেটাতে প্যাটার্ন pattern
v.oddou

উত্তর:


80

এখানে কমপক্ষে একটি মামলা দেওয়া হল:

struct foo {
  template<class T>
  operator T() const {
    std::cout << sizeof(T) << "\n";
    return {};
  }
};

যদি আপনি এটি করেন তবে foo f; int x = f; double y = f;টাইপ তথ্যটি "পিছনের দিকে" প্রবাহিত হবে Tযা ভিতরে রয়েছে তা বের করার জন্য operator T

আপনি এটি আরও উন্নত উপায়ে ব্যবহার করতে পারেন:

template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
  F f;
  template<class T>
  operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
  return deduce_return_t{ [&](auto ret){
    using R=typename decltype(ret)::type;
    return R{ std::forward<Args>(args)... };
  }};
}

তাই এখন আমি করতে পারি

std::vector<int> v = construct_from( 1, 2, 3 );

এবং এটি কাজ করে।

অবশ্যই, কেন না কেন {1,2,3}? ভাল, {1,2,3}একটি অভিব্যক্তি নয়।

std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );

যা স্বীকার করে নিন, এর জন্য আরও কিছুটা জাদুকরী প্রয়োজন: লাইভ উদাহরণ । (আমাকে ছাড়ের ফিরতি একটি SFINAE চেক করতে হবে, তারপরে এফটিকে SFINAE বান্ধব করে তুলতে হবে, এবং আমাকে অনুমান_আরক্ষক_আপনার টি তে স্ট্যান্ড :: আরম্ভকারী_লিস্ট ব্লক করতে হবে)


খুব আকর্ষণীয় উত্তর, এবং আমি একটি নতুন কৌশল শিখেছি তাই আপনাকে অনেক ধন্যবাদ! আপনার উদাহরণটি সংকলন করতে আমাকে একটি টেম্পলেট ছাড়ের গাইডলাইন যোগ করতে হয়েছিল , তবে এটি ছাড়া এটি কোনও কবজির মতো কাজ করে!
ম্যাসিমিলিয়ানো

4
&&উপর কোয়ালিফায়ার operator T()একটি দুর্দান্ত স্পর্শ হয়; এটি এখানে অপব্যবহার করা autoহলে সংকলনের ত্রুটির কারণ হয়ে দরিদ্র মিথস্ক্রিয়া এড়াতে সহায়তা করে auto
জাস্টিন

4
এটি খুব চিত্তাকর্ষক, আপনি কি আমাকে উদাহরণের মধ্যে কিছু রেফারেন্স / ধারণাটির সাথে কথা বলতে পারেন? অথবা হতে পারে এটি আসল :) ...
llllllllll

4
@ লিলি কোন ধারণা? আমি 5 গণনা করছি: রিটার্নের ধরণের জন্য অপারেটর টি ব্যবহার করছেন? একটি ল্যাম্বডায় অনুদানপ্রাপ্ত প্রকারটি পাস করতে ট্যাগ ব্যবহার করছেন? রূপান্তরকারী অপারেটরগুলি নিজের প্লেসমেন্ট অবজেক্ট কনস্ট্রাকশন রোল করতে ব্যবহার করছেন? সব 4 সংযোগ করছেন?
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

4
@ লিলি থা "আরও উন্নত উপায়" উদাহরণটি হ'ল, আমি যেমন বলেছি, মাত্র 4 বা তাই ধারণা একসাথে আটকানো হয়েছে। আমি এই পোস্টের জন্য ফ্লাইতে গ্লুয়িং করেছি, তবে অবশ্যই আমি একসঙ্গে ব্যবহৃত অনেকগুলি জোড়া বা এমনকি তিনটিও দেখেছি। এটি যুক্তিসঙ্গতভাবে অস্পষ্ট কৌশলগুলির একটি গোছা (টোটসির অভিযোগ হিসাবে), তবে কোনও উপন্যাস নয়।
ইয়াক্ক - অ্যাডাম নেভ্রামাউন্ট

31

স্টিফান টি। লাভভেজ একটি টুইট বার্তায় তিনি যে মামলার কথা বলছিলেন তা ব্যাখ্যা করেছিলেন :

আমি যে কেসটির কথা ভাবছিলাম তা হ'ল আপনি কোথায় ওভারলোডেড / টেম্পলেটযুক্ত ফাংশনটির ঠিকানা নিতে পারেন এবং যদি এটি কোনও নির্দিষ্ট ধরণের ভেরিয়েবল শুরু করতে ব্যবহার করা হয়, তবে এটি আপনি যেটি চান তা ছিন্নমূল করবে। (কী বিশৃঙ্খলা সৃষ্টি করে তার একটি তালিকা রয়েছে))

আমরা ওভারলোডেড ফাংশনের ঠিকানায় সিপ্রেফারেন্স পৃষ্ঠা থেকে এর উদাহরণ দেখতে পাচ্ছি , আমি নীচে কয়েকটি বাদ দিয়েছি:

int f(int) { return 1; } 
int f(double) { return 2; }   

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
    g(f, f); // selects int f(int) for the 1st argument
             // and int f(double) for the second

     auto foo = []() -> int (*)(int) {
        return f; // selects int f(int)
    }; 

    auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}

মাইকেল পার্ক যোগ করেছে :

এটি কোনও কংক্রিটের প্রারম্ভিকভাবে সীমাবদ্ধ নয় not এটি আর্গুমেন্টের সংখ্যা থেকেও অনুমান করতে পারে

এবং এই লাইভ উদাহরণ সরবরাহ করে :

void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
          typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
          typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
  f(&overload, 1, 2);
}

যা আমি এখানে আরও কিছুটা ব্যাখ্যা করি ।


4
আমরা এটিকেও বর্ণনা করতে পারি: এমন ক্ষেত্রে যেখানে অভিব্যক্তির প্রসঙ্গ প্রসঙ্গে নির্ভর করে?
এমএম

20

আমি ওভারলোডেড ফাংশনগুলির স্থির castালাইতে বিশ্বাস করি যে প্রবাহটি স্বাভাবিক ওভারলোড রেজোলিউশনের মতো বিপরীত দিকে যায়। সুতরাং এর মধ্যে একটি পিছনে, আমার ধারণা।


7
আমি বিশ্বাস করি এটি সঠিক is এবং আপনি যখন কোনও ফাংশনটির নাম কোনও ফাংশন পয়েন্টার প্রকারে পাস করেন; টাইপ তথ্য প্রবাহের প্রেক্ষাপট থেকে প্রবাহিত হয় (আপনি যে ধরণের কাজটি নির্ধারণ করছেন / তৈরি / ইত্যাদি) পিছনে ফাংশনের নামে কোন ওভারলোড চয়ন করা হয়েছে তা নির্ধারণ করে।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.