অনন্য বেনামে ধরণের ভাষা কেন ডিজাইন করবেন?


92

এটি এমন একটি বিষয় যা আমাকে বরাবরই সি ++ ল্যাম্বদা এক্সপ্রেশনগুলির বৈশিষ্ট্য হিসাবে বগল করে চলেছে: সি ++ ল্যাম্বডা এক্সপ্রেশনটির ধরণটি অনন্য এবং বেনামে, আমি কেবল এটি লিখতে পারি না। এমনকি যদি আমি দুটি ল্যাম্বডাস তৈরি করি যা সিন্টেক্সিকভাবে হুবহু একই রকম হয় তবে ফলাফলগুলি পৃথক হিসাবে সংজ্ঞায়িত করা হয়। পরিণতিটি হ'ল, ক) ল্যাম্বডাস কেবলমাত্র টেম্পলেট ফাংশনগুলিতে যেতে পারে যা সংকলনের সময়, অবর্ণনীয় টাইপটিকে বস্তুর সাথে অতিক্রম করার অনুমতি দেয় এবং খ) যে ল্যাম্বডাস কেবল তখনই মুছে ফেলা হয় তা কেবল তখনই কার্যকর std::function<>

ঠিক আছে, তবে সি ++ এর ঠিক এইভাবেই, আমি সেই ভাষাটির একটি অপূর্ব বৈশিষ্ট্য হিসাবে এটি লিখতে প্রস্তুত ছিলাম। তবে, আমি কেবল শিখেছি যে মরিচা আপাতদৃষ্টিতে একই কাজ করে: প্রতিটি মরচে ফাংশন বা ল্যাম্বদা একটি অনন্য, বেনামে টাইপ করে। এবং এখন আমি ভাবছি: কেন?

সুতরাং, আমার প্রশ্নটি হ'ল:
ভাষার ডিজাইনার দৃষ্টিকোণ থেকে কোনও অনন্য, বেনামে টাইপের ধারণাটি কোনও ভাষায় প্রবর্তন করার সুবিধা কী?


6
সর্বদা হিসাবে ভাল প্রশ্ন কেন হয় না।
স্টারগেটর

31
"সেই ল্যাম্বডাস কেবল তখনই দরকারী যখন তারা স্টাড :: ফাংশন <> এর মাধ্যমে মুছে ফেলা হয়েছে -" না, তারা সরাসরি ছাড়া দরকারী std::function। একটি ল্যাম্বডা যা একটি টেম্পলেট ফাংশনে পাস করা হয়েছে সরাসরি জড়িত ছাড়াই কল করা যেতে পারে std::function। সংকলকটি তখন ল্যাম্বডাকে টেম্পলেট ফাংশনে ইনলাইন করতে পারে যা রানটাইম দক্ষতা উন্নত করবে।
এরলকোনিগ

4
আমার অনুমান, এটি কার্যকর ল্যাম্বডাটিকে সহজ করে তোলে এবং ভাষাটিকে বোঝার সহজ করে তোলে। যদি আপনি ঠিক একই ল্যাম্বডা এক্সপ্রেশনটিকে একই ধরণের ভাঁজ করার অনুমতি দিয়ে থাকেন { int i = 42; auto foo = [&i](){ return i; }; } { int i = 13; auto foo = [&i](){ return i; }; }তবে পাঠ্যগতভাবে সেগুলি একই রকম হওয়া সত্ত্বেও আপনাকে হ্যান্ডেল করার জন্য বিশেষ নিয়ম প্রয়োজন । যদি আপনি কেবল বলেন যে তারা সমস্ত অনন্য, আপনি এটি বের করার চেষ্টা করার জন্য চিন্তা করতে হবে না।
নাথান অলিভার

4
তবে আপনি পাশাপাশি একটি ল্যাম্বডাস টাইপের একটি নাম দিতে পারেন এবং এটি দিয়ে সমস্ত একই করতে পারেন। lambdas_type = decltype( my_lambda);
বৃহত্তম_প্রেম_আইএস 663035818

4
তবে জেনেরিক ল্যাম্বডায় এক ধরণের কী হওয়া উচিত [](auto) {}? এটি দিয়ে কি শুরু করতে হবে?
এভগ

উত্তর:


78

অনেক স্ট্যান্ডার্ড (বিশেষত সি ++) কম্পাইলারদের কাছ থেকে তারা কতটা দাবি করে তা হ্রাস করার পদ্ধতিকে গ্রহণ করে। সত্যই, তারা ইতিমধ্যে যথেষ্ট চাহিদা! এটির কাজ করার জন্য যদি তাদের কিছু নির্দিষ্ট না করতে হয়, তবে এটিকে বাস্তবায়ন সংজ্ঞায়িত করার প্রবণতা রয়েছে।

ল্যাম্বডাস যদি অনামী না হয়ে থাকেন তবে আমাদের তাদের সংজ্ঞা দিতে হবে। ভেরিয়েবলগুলি কীভাবে ক্যাপচার করা হয় সে সম্পর্কে এটি বড় কথা বলতে হবে। একটি ল্যাম্বডা ক্ষেত্রে বিবেচনা করুন [=](){...}। টাইপটি উল্লেখ করতে হবে যে ল্যাম্বডা আসলে কোন ধরণের প্রকৃতপক্ষে ক্যাপচার হয়েছিল, এটি নির্ধারণের জন্য অপ্রয়োজনীয় হতে পারে। এছাড়াও, যদি সংকলক সফলভাবে কোনও ভেরিয়েবলটিকে অপ্টিমাইজ করে? বিবেচনা:

static const int i = 5;
auto f = [i]() { return i; }

একটি অনুকূলকরণ সংকলক সহজেই সনাক্ত করতে পারে যে এর একমাত্র সম্ভাব্য মান iহ'ল 5, এবং এটির সাথে প্রতিস্থাপন করুন auto f = []() { return 5; }। তবে, প্রকারটি যদি নামহীন না হয় তবে এটি প্রকারটি পরিবর্তন করতে পারে বা সংকলকটিকে কম অপ্টিমাইজ করতে বাধ্য করতে পারে, iযদিও এটির আসলে এটির প্রয়োজন ছিল না। এটি জটিলতা এবং উপদ্রবগুলির একটি সম্পূর্ণ ব্যাগ যা ল্যাম্বডাস যা করতে চেয়েছিল তা কেবল প্রয়োজন হয় না।

এবং, অফ-কেসে আপনার আসলে একটি অ-বেনামে প্রকারের দরকার আছে, আপনি সর্বদা ক্লোজার ক্লাস নিজেই তৈরি করতে পারেন এবং ল্যাম্বডা ফাংশনের পরিবর্তে ফান্টারের সাথে কাজ করতে পারেন। সুতরাং, তারা ল্যাম্বডাস 99% কেস হ্যান্ডেল করতে পারে এবং আপনার নিজের সমাধানটি 1% এ রেখে দিতে পারে।


ডিডুকিপেটর মন্তব্যগুলিতে উল্লেখ করেছেন যে আমি অনন্যতার পরিচয় হিসাবে এত স্বাতন্ত্র্য হিসাবে সম্বোধন করি না। আমি স্বতন্ত্রতার সুবিধাগুলির সম্পর্কে কম নিশ্চিত, তবে এটি লক্ষণীয় যে নিম্নলিখিত ধরণেরগুলি অনন্য হলে নিম্নলিখিত ক্রিয়াকলাপটি স্পষ্ট হয় (ক্রিয়াটি দু'বার তাত্ক্ষণিকভাবে চালু করা হবে)।

int counter()
{
    static int count = 0;
    return count++;
}

template <typename FuncT>
void action(const FuncT& func)
{
    static int ct = counter();
    func(ct);
}

...
for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });

for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });

প্রকারগুলি অনন্য না হলে এই ক্ষেত্রে কী আচরণ হওয়া উচিত তা আমাদের নির্দিষ্ট করে দিতে হবে। এটা জটিল হতে পারে। নাম প্রকাশ না করার বিষয়টি নিয়ে উত্থাপিত কয়েকটি বিষয়ও স্বতন্ত্রতার জন্য এই ক্ষেত্রে তাদের কুরুচিপূর্ণ মাথা উঁচু করে।


মনে রাখবেন যে এটি কোনও সংকলক প্রয়োগকারীটির জন্য কাজ সংরক্ষণের বিষয়ে নয়, তবে মানক রক্ষণাবেক্ষণকারীদের জন্য কাজ বাঁচানোর কাজ। সংকলকটিকে এখনও তার নির্দিষ্ট প্রয়োগের জন্য উপরের সমস্ত প্রশ্নের উত্তর দিতে হবে, তবে সেগুলি স্ট্যান্ডার্ডে নির্দিষ্ট করা হয়নি।
কমিকসান্স এমএমএস

4
@ComicSansMS একটি সংকলক বাস্তবায়ন করার সময় এই জাতীয় জিনিসগুলি একসাথে রেখে দেওয়া যখন আপনার প্রয়োগটি অন্য কারও মানের সাথে ফিট করে না far তবে তা আরও সহজ। অভিজ্ঞতা থেকে বলতে গিয়ে এটা প্রায়ই হয় পর্যন্ত overspecify কার্যকারিতা একটি মান রক্ষণাবেক্ষণকারী অনেক সহজ তুলনায় এটি ন্যূনতম পরিমাণ এখনও আপনার ভাষায় বাইরে আকাঙ্ক্ষিত কার্যকারিতা পেয়ে নির্দিষ্ট করার খুঁজতে চেষ্টা হয়। একটি চমৎকার কেস স্টাডি হিসাবে, এখনও মেমরি_অর্ডার_সংশ্লিষ্টটিকে এটিকে কার্যকর করার সময় (কিছু কিছু স্থাপত্যের উপর) প্রশ্রয় এড়াতে তারা কতটা কাজ করতে পেরেছিল তা দেখুন
কর্ট

4
অন্য সবার মতো, আপনি বেনামে জন্য একটি বাধ্যতামূলক মামলা করেন । তবে এটিকেও অনন্য হতে বাধ্য করার জন্য এটি কি এত ভাল ধারণা ?
হস্তান্তরকারী

এটি এখানে গুরুত্বপূর্ণ সংকলকটির জটিলতা নয়, তবে উত্পন্ন কোডের জটিলতা। মূল বিষয়টি সংকলকটিকে সহজতর করার জন্য নয়, তবে এটি সমস্ত ক্ষেত্রে অনুকূলিত করার জন্য এবং লক্ষ্য প্ল্যাটফর্মের জন্য প্রাকৃতিক কোড উত্পাদন করার জন্য পর্যাপ্ত উইগল রুম দেওয়ার জন্য।
জান হুডেক

আপনি একটি স্থির পরিবর্তনশীল ক্যাপচার করতে পারবেন না।
রুসলান

70

লাম্বডাস কেবল ফাংশন নয়, এগুলি একটি ফাংশন এবং একটি রাষ্ট্র । সুতরাং সি ++ এবং মরিচ উভয়ই কল অপারেটরের ( operator()সি ++ তে, Fn*মরিচায় তিনটি বৈশিষ্ট্যযুক্ত) একটি বস্তু হিসাবে তাদের প্রয়োগ করে ।

মূলত, [a] { return a + 1; }সি ++ ডিজুগারগুলিতে এমন কিছু

struct __SomeName {
    int a;

    int operator()() {
        return a + 1;
    }
};

তারপরে __SomeNameল্যাম্বদা কোথায় ব্যবহৃত হয় তার একটি উদাহরণ ব্যবহার করে।

|| a + 1মরিচায় থাকাকালীন, মরিচাতে যেমন কিছু হবে তেমনই হবে

{
    struct __SomeName {
        a: i32,
    }

    impl FnOnce<()> for __SomeName {
        type Output = i32;
        
        extern "rust-call" fn call_once(self, args: ()) -> Self::Output {
            self.a + 1
        }
    }

    // And FnMut and Fn when necessary

    __SomeName { a }
}

এর অর্থ এই যে সবচেয়ে lambdas আবশ্যক আছে বিভিন্ন ধরনের।

এখন, আমরা কয়েকটি উপায় করতে পারি:

  • বেনামি ধরণের সাথে, যা উভয় ভাষাই প্রয়োগ করে। এর আর একটি পরিণতি হ'ল সমস্ত ল্যাম্বডাসের অবশ্যই আলাদা ধরণের থাকতে হবে। তবে ভাষা ডিজাইনারদের জন্য এটির সুস্পষ্ট সুবিধা রয়েছে: ল্যাম্বডাসকে ভাষার ইতিমধ্যে বিদ্যমান সরল অংশগুলি ব্যবহার করে বর্ণনা করা যেতে পারে। তারা ইতিমধ্যে ভাষার বিদ্যমান বিটগুলির চারপাশে কেবল সিনট্যাক্স চিনি।
  • ল্যাম্বদা প্রকারের নামকরণের জন্য কিছু বিশেষ সিনট্যাক্স সহ: এটি অবশ্য প্রয়োজনীয় নয় যেহেতু ল্যাম্বডাস ইতিমধ্যে সি ++ তে টেমপ্লেটগুলির সাথে বা জেনেরিকগুলি এবং Fn*জং এর বৈশিষ্ট্যগুলির সাথে ব্যবহার করা যেতে পারে । কোনও ভাষাই আপনাকে লাম্বাডাস ( std::functionসি ++ বা Box<Fn*>মরচে থাকা) ব্যবহার করতে টাইপ-মুছে ফেলতে বাধ্য করে না ।

এছাড়াও লক্ষ করুন যে উভয় ভাষাই একমত যে তুচ্ছ ল্যাম্বডাস যা প্রসঙ্গ ক্যাপচার করে না ফাংশন পয়েন্টারে রূপান্তরিত হতে পারে।


সরল বৈশিষ্ট্য ব্যবহার করে কোনও ভাষার জটিল বৈশিষ্ট্য বর্ণনা করা খুব সাধারণ। উদাহরণস্বরূপ সি ++ এবং মরিচা উভয়ের উভয়ই রেঞ্জের লুপ রয়েছে এবং তারা উভয়ই অন্যান্য বৈশিষ্ট্যগুলির জন্য এগুলি সিনট্যাক্স চিনির হিসাবে বর্ণনা করে।

সি ++ সংজ্ঞা দেয়

for (auto&& [first,second] : mymap) {
    // use first and second
}

সমতুল্য হিসাবে

{

    init-statement
    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement

    }

} 

এবং মরিচা সংজ্ঞায়িত করে

for <pat> in <head> { <body> }

সমতুল্য হিসাবে

let result = match ::std::iter::IntoIterator::into_iter(<head>) {
    mut iter => {
        loop {
            let <pat> = match ::std::iter::Iterator::next(&mut iter) {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => break
            };
            SemiExpr(<body>);
        }
    }
};

যা এগুলি মানুষের পক্ষে আরও জটিল বলে মনে হয় তা কোনও ভাষা ডিজাইনার বা সংকলক উভয়ই সহজ।


15
@ cmaster-reinstatemonica একটি বাছাই ফাংশন জন্য তুলনামূলক যুক্তি হিসাবে একটি ল্যাম্বদা পাস বিবেচনা করুন। আপনি কি এখানে ভার্চুয়াল ফাংশন কলগুলির একটি ওভারহেড চাপিয়ে দিতে চান?
ড্যানিয়েল ল্যাঙ্গার

4
@ cmaster-reinstatemonica কারণ C ++ এ ভার্চুয়াল-বাই-ডিফল্ট কিছুই নেই
ক্যালাথ

4
@ মাস্টার - আপনার অর্থ ল্যাম্বডাসের সমস্ত ব্যবহারকারীকে গতিশীল ডিপ্যাচের জন্য অর্থ প্রদান করতে বাধ্য করা, এমনকি যখন তাদের এটির প্রয়োজন হবে না?
গল্পগ্রাহক - আনস্ল্যান্ডার মনিকা

4
@ cmaster-reinstatemonica আপনি যে সেরাটি পাবেন তা হ'ল ভার্চুয়াল থেকে বেছে নেওয়া। অনুমান করুন, std::functionএটি কি করে
কালেথ

9
@ সিমেস্টার-রিস্টেস্টেমোনিকার যে কোনও প্রক্রিয়া যেখানে আপনি ফাংশনটি পুনঃনির্দেশ করতে পারেন সেখানে রানটাইম ওভারহেডের পরিস্থিতি থাকবে। এটি সি ++ উপায় নয়। আপনি নির্বাচন করেছেনstd::function
কালেথ

13

(ক্যালাথের উত্তরে যুক্ত করা, তবে একটি মন্তব্যে ফিট করার জন্য খুব দীর্ঘ))

ল্যাম্বডা এক্সপ্রেশনটি কোনও বেনামি স্ট্রাক্টের জন্য কেবল সিনট্যাকটিক চিনি (ভলডেমর্ট টাইপ, কারণ আপনি এর নামটি বলতে পারবেন না)।

আপনি এই কোড স্নিপেটে একটি বেনামি কাঠামো এবং একটি ল্যাম্বডা নাম প্রকাশের মধ্যে মিল খুঁজে পেতে পারেন:

#include <iostream>
#include <typeinfo>

using std::cout;

int main() {
    struct { int x; } foo{5};
    struct { int x; } bar{6};
    cout << foo.x << " " << bar.x << "\n";
    cout << typeid(foo).name() << "\n";
    cout << typeid(bar).name() << "\n";
    auto baz = [x = 7]() mutable -> int& { return x; };
    auto quux = [x = 8]() mutable -> int& { return x; };
    cout << baz() << " " << quux() << "\n";
    cout << typeid(baz).name() << "\n";
    cout << typeid(quux).name() << "\n";
}

যদি এটি এখনও ল্যাম্বডায় অসন্তুষ্ট হয় তবে এটি বেনামে কাঠামোর জন্য একইভাবে অসন্তুষ্ট হওয়া উচিত।

কিছু ভাষায় এক ধরণের হাঁসের টাইপিংয়ের অনুমতি দেওয়া হয় যা কিছুটা নমনীয় এবং এমনকি সি ++ টেমপ্লেট রয়েছে যা কোনও টেমপ্লেট থেকে কোনও বস্তু তৈরি করতে সত্যই সহায়তা করে না যার সদস্য ক্ষেত্র রয়েছে যা একটি ল্যাম্বডাকে ব্যবহারের পরিবর্তে সরাসরি প্রতিস্থাপন করতে পারে std::functionমোড়ক


4
আপনাকে ধন্যবাদ, ল্যাম্বডাসকে সি ++ এ যেভাবে সংজ্ঞায়িত করা হয়েছে তার পিছনে যুক্তিটির বিষয়ে সত্যই কিছুটা আলোকপাত হয়েছে (আমি "ভলডেমর্ট টাইপ" :-) শব্দটি মনে করতে পারি)। তবে, প্রশ্নটি রয়ে গেছে: কোনও ভাষা ডিজাইনারের দৃষ্টিতে এর সুবিধা কী ?
মাস্টার -

4
আপনি এই int& operator()(){ return x; }
স্ট্রাকগুলিতে

4
@ cmaster-reinstatemonica • অনুমানমূলকভাবে ... বাকী সি ++ এমনভাবে আচরণ করে। ল্যাম্বডাস তৈরির জন্য কিছু ধরণের "পৃষ্ঠের আকৃতি" ব্যবহারের জন্য হাঁসের টাইপিং বাকী ভাষা থেকে খুব আলাদা কিছু হবে। ল্যাম্বডাসের জন্য ভাষায় এই জাতীয় সুবিধা যুক্ত করা সম্ভবত পুরো ভাষার জন্যই সাধারণীকরণ হিসাবে বিবেচিত হবে এবং এটি একটি সম্ভাব্য বিশাল ব্রেকিং পরিবর্তন হবে। কেবল ল্যাম্বডাসের জন্য এই জাতীয় সুযোগ ছাড়াই বাকী সি ++ এর দৃ strongly়-ইশ টাইপিংয়ের সাথে খাপ খায়।
এলজয়

প্রযুক্তিগতভাবে একটি ভলডেমর্ট টাইপ হবে auto foo(){ struct DarkLord {} tom_riddle; return tom_riddle; }, কারণ বাইরে fooকিছুই শনাক্তকারী ব্যবহার করতে পারে নাDarkLord
ক্যালথ

@ কাস্টার-রিস্টেস্টেমোনিকা দক্ষতা, বিকল্পটি বাক্স এবং গতিশীলভাবে প্রতিটি ল্যাম্বডাকে প্রেরণ করা হবে (এটিকে গাদাতে বরাদ্দ করুন এবং তার সঠিক প্রকারটি মুছুন)। এখন আপনি যেমন লক্ষ করেছেন যে সংকলকটি বেনামে প্রকারের লম্বা লম্বা প্রতিলিপি তৈরি করতে পারে তবে আপনি এখনও সেগুলি লিখতে সক্ষম হবেন না এবং এটি খুব সামান্য লাভের জন্য উল্লেখযোগ্য কাজ প্রয়োজন, সুতরাং প্রতিক্রিয়াগুলি সত্যিকার পক্ষে নয়।
মাস্কলিন

10

অনন্য বেনামে ধরণের ভাষা কেন ডিজাইন করবেন ?

কারণ এমন কিছু মামলা রয়েছে যেখানে নামগুলি অপ্রাসঙ্গিক এবং কার্যকর নয় এমনকি প্রতিক্রিয়াশীলও নয়। এক্ষেত্রে তাদের অস্তিত্বকে বিমূর্ত করার ক্ষমতাটি দরকারী কারণ এটি নাম দূষণ হ্রাস করে এবং কম্পিউটার বিজ্ঞানের দুটি কঠিন সমস্যার মধ্যে একটির সমাধান করে (কীভাবে কীভাবে নামকরণ করবেন)। একই কারণে অস্থায়ী বস্তুগুলি কার্যকর।

ল্যাম্বদা

স্বতন্ত্রতা কোনও বিশেষ ল্যাম্বডা জিনিস বা বেনামি ধরণের বিশেষ জিনিসও নয়। এটি ভাষাতে নামকরণ করা প্রকারের ক্ষেত্রেও প্রযোজ্য। নিম্নলিখিত বিবেচনা করুন:

struct A {
    void operator()(){};
};

struct B {
    void operator()(){};
};

void foo(A);

নোট যে আমি পাস করতে পারে না Bবা foo, যদিও ক্লাস অভিন্ন। এই একই সম্পত্তি নামবিহীন প্রকারের জন্য প্রযোজ্য।

ল্যাম্বডাস কেবলমাত্র টেম্পলেট ফাংশনগুলিতে যেতে পারে যা সংকলনের সময়, অবর্ণনীয় টাইপটিকে অবজেক্টের সাথে পাশ করার অনুমতি দেয় ... স্টাডি :: ফাংশন <> এর মাধ্যমে মুছে ফেলা হয়।

ল্যাম্বডাসের সাবসেটের জন্য তৃতীয় বিকল্প রয়েছে: নন-ক্যাপচারিং ল্যাম্বডাস ফাংশন পয়েন্টারে রূপান্তরিত হতে পারে।


মনে রাখবেন যে কোনও বেনামি ধরণের সীমাবদ্ধতা যদি কোনও ব্যবহারের ক্ষেত্রে সমস্যা হয় তবে সমাধানটি সহজ: পরিবর্তে নামকরণ করা টাইপ ব্যবহার করা যেতে পারে। ল্যাম্বডাস এমন কিছু করেন না যা নামী শ্রেণীর সাথে করা যায় না।


10

কর্ট আম্মনের গৃহীত উত্তরটি ভাল তবে আমি মনে করি বাস্তবায়নের বিষয়ে আরও একটি গুরুত্বপূর্ণ বিষয় রয়েছে।

ধরুন আমার দুটি পৃথক অনুবাদ ইউনিট রয়েছে, "ওয়ান সিপিপি" এবং "two.cpp"।

// one.cpp
struct A { int operator()(int x) const { return x+1; } };
auto b = [](int x) { return x+1; };
using A1 = A;
using B1 = decltype(b);

extern void foo(A1);
extern void foo(B1);

দুটি ওভারলোড fooএকই শনাক্তকারী ( foo) ব্যবহার করে তবে বিভিন্ন ম্যাংলেড নাম রয়েছে। (পসিক্স-ইশ সিস্টেমে ব্যবহৃত ইটানিয়াম এবিআইতে, ম্যাঙ্গলেড নামগুলি রয়েছে _Z3foo1Aএবং এই বিশেষ ক্ষেত্রে, _Z3fooN1bMUliE_E))

// two.cpp
struct A { int operator()(int x) const { return x + 1; } };
auto b = [](int x) { return x + 1; };
using A2 = A;
using B2 = decltype(b);

void foo(A2) {}
void foo(B2) {}

সি ++ সংকলককে অবশ্যই নিশ্চিত করতে হবে যে void foo(A1)"two.cpp" এ থাকা ম্যাংলেড নামটি extern void foo(A2)"ওয়ান সিপিপি" এর ম্যাংলেড নামের মতো , যাতে আমরা দুটি অবজেক্ট ফাইলকে একসাথে যুক্ত করতে পারি। এটি দুটি ধরণের "একই ধরণের" হওয়ার শারীরিক অর্থ : এটি মূলত পৃথকভাবে সংকলিত অবজেক্ট ফাইলগুলির মধ্যে এবিআই-সামঞ্জস্যতা সম্পর্কে।

সি ++ সংকলকটি এটির প্রয়োজন হয় নাB1 এবং B2এটি "একই ধরণের" ensure (আসলে, এগুলি নিশ্চিত করা দরকার যে তারা বিভিন্ন ধরণের; তবে এটি এখনকার মতো গুরুত্বপূর্ণ নয়))


সংকলক A1এবং A2এটি "একই ধরণের" তা নিশ্চিত করতে কোন শারীরিক প্রক্রিয়া ব্যবহার করে ?

এটি কেবল টাইপিডেফগুলির মধ্য দিয়ে যায় এবং তারপরে প্রকারটির সম্পূর্ণরূপে যোগ্যতাসম্পন্ন নামটি দেখায়। এটি একটি শ্রেণীর নামযুক্ত A। (ঠিক আছে, ::Aযেহেতু এটি বিশ্বব্যাপী নেমস্পেসে রয়েছে)) সুতরাং এটি উভয় ক্ষেত্রেই একই রকম। এটা বুঝতে সহজ। আরও গুরুত্বপূর্ণ, এটি কার্যকর করা সহজ । যদি দুটি শ্রেণী ধরনের একই ধরনের হয় দেখার জন্য, আপনাকে তাদের নাম গ্রহণ করা এবং একটি strcmp। কোনও ফাংশনের মাংডেল নামের একটি শ্রেণির ধরণটি ছড়িয়ে দেওয়ার জন্য, আপনি তার নামে অক্ষরের সংখ্যা লিখুন, তারপরে সেই অক্ষরগুলি অনুসরণ করুন।

সুতরাং, নামযুক্ত প্রকারগুলি ম্যাঙ্গেল করা সহজ।

কি শারীরিক প্রক্রিয়া পারে তা নিশ্চিত কম্পাইলার ব্যবহার B1এবং B2"একই ধরনের," একটি প্রকল্পিত দুনিয়া আছে যেখানে সি ++ তাদের প্রয়োজনীয় একই ধরনের হতে হবে?

ওয়েল, এটা ধরনের নাম ব্যবহার করতে পারে না কারণ টাইপ না আছে একটি নাম।

হতে পারে এটি কোনওভাবে ল্যাম্বদার দেহের পাঠ্যটি এনকোড করতে পারে । তবে এটি এক ধরনের বিশ্রী হবে, কারণ আসলে b"ওয়ান.সি.পি.পি." এর bমধ্যে "two.cpp": "ওয়ান.সি.পি." আছে x+1এবং "two.cpp" আছে তার থেকে সূক্ষ্মভাবে আলাদা x + 1। সুতরাং আমাদের এমন একটি নিয়ম নিয়ে আসতে হবে যাতে বলা হয় যে এই শ্বেত স্পেসের পার্থক্য কোনও বিষয় নয়, বা এটি করে (সর্বোপরি তাদেরকে বিভিন্ন ধরণের করে তোলে), বা সম্ভবত এটি করে (সম্ভবত প্রোগ্রামটির বৈধতা বাস্তবায়ন-সংজ্ঞায়িত , বা হতে পারে এটি "রোগ নির্ধারিত কোনও ডায়াগনস্টিকের প্রয়োজন নেই")। যাইহোক,A

অসুবিধা থেকে মুক্তির সহজতম উপায়টি হ'ল প্রতিটি ল্যাম্বডা এক্সপ্রেশন একটি অনন্য ধরণের মান তৈরি করে। তারপর বিভিন্ন অনুবাদ ইউনিটে সংজ্ঞায়িত দুটি ল্যাম্বদা প্রকারগুলি অবশ্যই একই ধরণের নয় । একটি একক অনুবাদ ইউনিটের মধ্যে, আমরা উত্স কোডের শুরু থেকে কেবল গণনা করে ল্যাম্বদা প্রকারগুলিকে "নাম" দিতে পারি:

auto a = [](){};  // a has type $_0
auto b = [](){};  // b has type $_1
auto f(int x) {
    return [x](int y) { return x+y; };  // f(1) and f(2) both have type $_2
} 
auto g(float x) {
    return [x](int y) { return x+y; };  // g(1) and g(2) both have type $_3
} 

অবশ্যই এই নামের অর্থ কেবল এই অনুবাদ ইউনিটের মধ্যে রয়েছে। এই টিইউ $_0সবসময় অন্য কোনও টিইউর থেকে সবসময় আলাদা ধরণের থাকে $_0যদিও এই টিইউ struct Aসবসময় অন্য কোনও টিইউর মতো একই ধরণের struct A

যাইহোক, লক্ষ্য করুন যে আমাদের "ল্যাম্বডাটির পাঠ্যটি এনকোড করুন" ধারণার মধ্যে আরও একটি সূক্ষ্ম সমস্যা ছিল: ল্যাম্বডাস $_2এবং $_3ঠিক একই পাঠ্যটি নিয়ে গঠিত , তবে তাদের স্পষ্টতই একই ধরণের হিসাবে বিবেচনা করা উচিত নয় !


যাইহোক, সি ++ এর মতো একটি স্বেচ্ছাসেবী সি ++ এক্সপ্রেশনটির পাঠ্যকে কীভাবে আঁকতে হয় তা জানতে সংকলকটির প্রয়োজন হয়

template<class T> void foo(decltype(T())) {}
template void foo<int>(int);  // _Z3fooIiEvDTcvT__EE, not _Z3fooIiEvT_

কিন্তু সি ++ (এখনও) কোনও স্বেচ্ছাসেবী সি ++ বিবৃতি ম্যাঙ্গেল করতে হবে তা জানতে সংকলকটির প্রয়োজন নেই । decltype([](){ ...arbitrary statements... })এমনকি সি ++ ২০ তেও দুর্গঠিত।


এছাড়াও নোটিশ যে এটা সহজ দিতে একটি নামহীন টাইপ ব্যবহার করার একটি স্থানীয় ওরফে typedef/ using। আমার অনুভূতি আছে যে আপনার প্রশ্নটি এমন কিছু করার চেষ্টা করে উত্থাপিত হয়েছিল যা এরকমভাবে সমাধান হতে পারে।

auto f(int x) {
    return [x](int y) { return x+y; };
}

// Give the type an alias, so I can refer to it within this translation unit
using AdderLambda = decltype(f(0));

int of_one(AdderLambda g) { return g(1); }

int main() {
    auto f1 = f(1);
    assert(of_one(f1) == 2);
    auto f42 = f(42);
    assert(of_one(f42) == 43);
}

সংযোজন সম্পাদনা করুন: অন্যান্য উত্তরের উপর আপনার কিছু মন্তব্য পড়ে, মনে হচ্ছে আপনি কেন ভাবছেন

int add1(int x) { return x + 1; }
int add2(int x) { return x + 2; }
static_assert(std::is_same_v<decltype(add1), decltype(add2)>);
auto add3 = [](int x) { return x + 3; };
auto add4 = [](int x) { return x + 4; };
static_assert(not std::is_same_v<decltype(add3), decltype(add4)>);

এটি কারণ ক্যাপচারহীন ল্যাম্বডাসগুলি ডিফল্ট-গঠনমূলক ti (সি ++ তে কেবল সি ++ 20 হিসাবে রয়েছে তবে এটি সর্বদা ধারণাগতভাবে সত্য)

template<class T>
int default_construct_and_call(int x) {
    T t;
    return t(x);
}

assert(default_construct_and_call<decltype(add3)>(42) == 45);
assert(default_construct_and_call<decltype(add4)>(42) == 46);

আপনি চেষ্টা যদি default_construct_and_call<decltype(&add1)>, tএকটি ডিফল্ট-সক্রিয়া ফাংশন পয়েন্টার হবে এবং আপনি সম্ভবত segfault চাই। এটি, মত, দরকারী নয়।


" প্রকৃতপক্ষে, এগুলি নিশ্চিত করা দরকার যে তারা বিভিন্ন ধরণের; তবে এটি এখনকার মতো গুরুত্বপূর্ণ নয় " "আমি অবাক হয়েছি যে, সমতুল্যভাবে সংজ্ঞায়িত হলে স্বতন্ত্রতা জোর করার কোনও উপযুক্ত কারণ আছে কিনা।
হস্তান্তরকারী

ব্যক্তিগতভাবে আমি মনে করি সম্পূর্ণ সংজ্ঞায়িত আচরণ অনির্দিষ্ট আচরণের চেয়ে সর্বদা ভাল (প্রায়?) ভাল। "এই দুটি ফাংশন পয়েন্টার কি সমান? আচ্ছা, কেবলমাত্র যদি এই দুটি টেম্পলেট ইনস্ট্যান্টেশন একই ফাংশন হয়, যা কেবলমাত্র যদি এই দুটি ল্যাম্বদা প্রকারগুলি একই ধরণের হয় তবে এটি সত্য যা কেবল সংকলক তাদের একীভূত করার সিদ্ধান্ত নিয়েছে।" আইকি! (তবে লক্ষ্য করুন যে স্ট্রিং-আক্ষরিক মার্জিংয়ের সাথে আমাদের ঠিক একই রকম পরিস্থিতি রয়েছে এবং সেই পরিস্থিতি সম্পর্কে কেউই বিভ্রান্ত হয় না। সুতরাং আমি সন্দেহ করি যে
সংকলকটিকে

ভাল, দুটি সমতুল্য ফাংশন (যেমন-বাদে) অভিন্ন হতে পারে তাও একটি দুর্দান্ত প্রশ্ন। স্ট্যান্ডার্ডের ভাষাটি নিখরচায় এবং / অথবা স্থির ফাংশনের জন্য খুব স্পষ্ট নয়। তবে এটাই এখানে সুযোগের বাইরে।
হস্তান্তরকারী

অবিলম্বে, মার্জ ফাংশন সম্পর্কে এলএলভিএম মেলিং তালিকায় এই মাসে খুব আলোচনা হয়েছে । ক্ল্যাংয়ের কোডজেন সম্পূর্ণ খালি মৃত দেহের সাথে প্রায়শই "দুর্ঘটনায়" একীভূত হয়ে ফাংশন সৃষ্টি করবে: Godbolt.org/z/obT55b এটি প্রযুক্তিগতভাবে মেনে চলতে পারে না এবং আমি মনে করি তারা সম্ভবত এলএলভিএমকে এটি করা বন্ধ করবে। তবে হ্যাঁ, সম্মত, ফাংশনের ঠিকানাগুলি মার্জ করাও একটি জিনিস।
কুক্সপ্লসোন

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

9

সি ++ ল্যাম্বডাসের স্বতন্ত্র ক্রিয়াকলাপগুলির জন্য স্বতন্ত্র প্রকারের প্রয়োজন , কারণ সি ++ স্থিতিশীলভাবে বেঁধে দেয়। এগুলি কেবল অনুলিপি / মুভ-কনস্ট্রাকটেবল, তাই বেশিরভাগ ক্ষেত্রে আপনাকে তাদের ধরণের নাম দেওয়ার দরকার নেই। তবে এগুলি কিছুটা বাস্তবায়ন বিশদ।

আমি নিশ্চিত নই যে সি # ল্যাম্বডাসের কোনও প্রকার রয়েছে কিনা, কারণ তারা "বেনামে ফাংশন এক্সপ্রেশন" এবং এগুলি সঙ্গে সঙ্গে একটি সামঞ্জস্যপূর্ণ প্রতিনিধি প্রকার বা অভিব্যক্তি গাছের ধরণে রূপান্তরিত হয়। যদি এটি করেন তবে এটি সম্ভবত একটি অপ্রচলিত প্রকার।

সি ++ এরও বেনামে স্ট্রাক্ট রয়েছে, যেখানে প্রতিটি সংজ্ঞা একটি অনন্য ধরণের দিকে পরিচালিত করে। এখানে নামটি অপ্রকাশনীয় নয়, স্ট্যান্ডার্ড সম্পর্কিত যতটা আছে কেবল এটির অস্তিত্ব নেই।

সি # এর বেনামে ডেটা টাইপ রয়েছে , যা তারা সাবধানতার সাথে তাদের সংজ্ঞায়িত স্কোপ থেকে পালাতে নিষেধ করে। বাস্তবায়ন তাদেরও একটি অনন্য, অপ্রকাশ্য নাম দেয়।

প্রোগ্রামারকে একটি বেনামি ধরণের সংকেত রয়েছে যেগুলি তাদের প্রয়োগের ভিতরে ঘুরবে না।

পাশে:

আপনি একটি ল্যাম্বদার ধরণের নাম দিতে পারেন

auto foo = []{}; 
using Foo_t = decltype(foo);

আপনার যদি কোনও ক্যাপচার না থাকে তবে আপনি কোনও ফাংশন পয়েন্টার টাইপ ব্যবহার করতে পারেন

void (*pfoo)() = foo;

4
প্রথম উদাহরণ কোডটি এখনও Foo_t = []{};কেবলমাত্র Foo_t = fooএবং অন্য কিছুকে মঞ্জুরি দেয় না।
মাস্টার -

4
@ cmaster-reinstatemonica এর কারণ টাইপটি ডিফল্ট কনস্ট্রাকটেবল নয়, নাম প্রকাশের কারণে নয়। আমার অনুমান যে কোনও কারিগরি কারণ হিসাবে আপনাকে মনে রাখতে হবে এমন কোনও কোণার বৃহত্তর সেট না এড়ানো নিয়ে যতটা করা সম্ভব is
কালেথ

6

বেনামি ধরণের ব্যবহার কেন?

সংকলক দ্বারা স্বয়ংক্রিয়ভাবে উত্পাদিত হয় এমন ধরণের জন্য পছন্দটি হয় (1) প্রকারের নামের জন্য কোনও ব্যবহারকারীর অনুরোধকে সম্মান জানায়, বা (2) সংকলকটিকে তার নিজের থেকে একটি চয়ন করতে দিন।

  1. পূর্ববর্তী ক্ষেত্রে, ব্যবহারকারী প্রতিটি সময় এইরকম কন্সট্রাক্ট উপস্থিত হওয়ার সাথে সাথে স্পষ্টভাবে একটি নাম সরবরাহ করবেন বলে আশা করা হচ্ছে (সি ++ / মরিচ: যখনই ল্যাম্বডা সংজ্ঞায়িত করা হয়; মরিচ: যখনই কোনও ফাংশন সংজ্ঞায়িত করা হয়)। এটি প্রতিটি সময় সরবরাহকারীর পক্ষে ক্লান্তিকর বিবরণ এবং বেশিরভাগ ক্ষেত্রেই নামটি আর কখনও উল্লেখ করা হয় না। এইভাবে সংকলকটি এটির জন্য স্বয়ংক্রিয়ভাবে কোনও নাম বের করতে দেয় এবং বিদ্যমান বৈশিষ্ট্যগুলি ব্যবহার করে decltypeবা প্রয়োজনীয় যেখানে কয়েকটি স্থানে প্রকারটি উল্লেখ করে তা টাইপ করে sense

  2. পরবর্তী ক্ষেত্রে, সংকলকটির টাইপের জন্য একটি অনন্য নাম চয়ন করা প্রয়োজন, এটি সম্ভবত একটি অস্পষ্ট, অপঠনযোগ্য নাম যেমন __namespace1_module1_func1_AnonymousFunction042। ভাষা ডিজাইনার এই নামটি কীভাবে মহিমান্বিত এবং সূক্ষ্ম বিশদে তৈরি করা হয়েছে তা সুনির্দিষ্টভাবে উল্লেখ করতে পারে, তবে এটি ব্যবহারকারীর কাছে একটি বাস্তবায়ন বিশদটি অনাবশ্যকভাবে প্রকাশ করে যে কোনও বুদ্ধিমান ব্যবহারকারীর উপর নির্ভর করতে পারে না, যেহেতু নামটি এমনকি গৌণ রিফ্যাক্টরদের ক্ষেত্রেও এই নামটি সন্দেহজনক নয়। এটি অযৌক্তিকভাবে ভাষাটির বিবর্তনেও বাধা দেয়: ভবিষ্যতের বৈশিষ্ট্য সংযোজনগুলি বিদ্যমান নাম প্রজন্মের অ্যালগরিদমকে পরিবর্তিত করতে পারে এবং পশ্চাদপটে সামঞ্জস্যতার সমস্যার দিকে নিয়ে যেতে পারে। সুতরাং, কেবলমাত্র এই বিশদটি বাদ দিতেই এটি বোধগম্য হয় এবং স্বতঃ উত্পাদিত ধরণটি ব্যবহারকারী দ্বারা অপরিবর্তনীয় as

অনন্য (স্বতন্ত্র) প্রকারগুলি কেন ব্যবহার করবেন?

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

উদাহরণস্বরূপ, সংকলকটি যে মুহুর্তটি দেখবে:

let f: __UniqueFunc042 = || { ... };  // definition of __UniqueFunc042 (assume it has a nontrivial closure)

/* ... intervening code */

let g: __UniqueFunc042 = /* some expression */;
g();

সংকলকটির পূর্ণ আত্মবিশ্বাস রয়েছে যা gঅবশ্যই অগত্যা থেকেই উদ্ভূত হওয়া উচিত f, এমনকি এর প্রমাণটি না জেনেও g। এটি gকলটিকে ডেভर्चুয়ালাইজড করার অনুমতি দেবে । ব্যবহারকারী এটিও জানত, যেহেতু ব্যবহারকারী fতথ্যের প্রবাহের মাধ্যমে অনন্য প্রকারের সংরক্ষণের জন্য দুর্দান্ত যত্ন নিয়েছে g

অগত্যা, এটি ব্যবহারকারী কী করতে পারে তা সীমাবদ্ধ করে f। ব্যবহারকারী লেখার স্বাধীনতায় নেই:

let q = if some_condition { f } else { || {} };  // ERROR: type mismatch

এটি দুটি স্বতন্ত্র প্রকারের (অবৈধ) একীকরণের দিকে পরিচালিত করবে।

এটির চারপাশে কাজ করার জন্য, ব্যবহারকারীটি __UniqueFunc042অনন্য-অনন্য প্রকারে আপকাস্ট করতে পারে &dyn Fn(),

let f2 = &f as &dyn Fn();  // upcast
let q2 = if some_condition { f2 } else { &|| {} };  // OK

এই ধরণের মুছে ফেলার মাধ্যমে বানানো ট্রেড-অফ হ'ল সংকলকটির পক্ষে &dyn Fn()যুক্তি জটিল করে। প্রদত্ত:

let g2: &dyn Fn() = /*expression */;

সংকলকটিকে নির্দ্বিধায় পরীক্ষা করতে /*expression */হয় নির্ধারণ করতে হবে যে অন্য কোনও ফাংশন (গুলি) g2থেকে উদ্ভূত কিনা fএবং সেই প্রবণতাটি যে পরিস্থিতিতে রয়েছে the অনেক পরিস্থিতিতে, কম্পাইলার ছেড়ে দিতে হবে পারেন: সম্ভবত মানব যে বলতে পারতাম g2সত্যিই থেকে আসে fসব পরিস্থিতিতে কিন্তু থেকে পথ fথেকে g2খুব পাঠোদ্ধার কম্পাইলার জন্য সংবর্ত ছিল, এর একটি ভার্চুয়াল কল ফলে g2হতাশাপূর্ণ কর্মক্ষমতা সঙ্গে।

জেনেরিক (টেমপ্লেট) ফাংশনে এই জাতীয় বস্তু সরবরাহ করা হলে এটি আরও স্পষ্ট হয়:

fn h<F: Fn()>(f: F);

এক কল যদি h(f)যেখানে f: __UniqueFunc042, তারপর hএকটি অনন্য ক্ষেত্রটিকেই বিশেষ হয়:

h::<__UniqueFunc042>(f);

এটি সংকলকটির hবিশেষ যুক্তির জন্য উপযুক্ত , এর জন্য বিশেষ কোড তৈরি করতে সক্ষম করে fএবং fপ্রেরণটি ইনডিল না হলে স্থির হওয়ার যথেষ্ট সম্ভাবনা রয়েছে।

বিপরীত দৃশ্যে, যেখানে কেউ কল h(f)করে f2: &Fn(), hততক্ষণ তাত্ক্ষণিকভাবে

h::<&Fn()>(f);

যা টাইপের সমস্ত ফাংশনের মধ্যে ভাগ করা হয় &Fn()। এর মধ্যে থেকে h, সংকলকটি ধরণের একটি অস্বচ্ছ ফাংশন সম্পর্কে খুব কম জানে &Fn()এবং তাই কেবল রক্ষণশীলভাবে fভার্চুয়াল প্রেরণের মাধ্যমে কল করতে পারে । স্থিতিশীলভাবে প্রেরণ করতে, সংকলকটিকে h::<&Fn()>(f)তার কল সাইটে কলটি ইনলাইন করতে হবে, যা hখুব জটিল হলে গ্যারান্টিযুক্ত নয় ।


নাম নির্বাচনের প্রথম অংশটি বিন্দুটি মিস করে: এই জাতীয় ধরণের কোনওটির নাম void(*)(int, double)নাও থাকতে পারে তবে আমি এটি লিখতে পারি। আমি এটিকে একটি নামহীন প্রকার বলব, একটি অনামী প্রকার নয়। এবং আমি __namespace1_module1_func1_AnonymousFunction042নাম ম্যাংলিংয়ের মতো ক্রিপ্টিক স্টাফগুলিতে কল করব যা অবশ্যই এই প্রশ্নের ক্ষেত্রের মধ্যে নয়। এই প্রশ্নটি এমন প্রকারগুলি সম্পর্কে যা প্রমিত দ্বারা গ্যারান্টিযুক্ত যা লিখিতভাবে লেখা অসম্ভব, কোনও প্রকারের সিনট্যাক্স প্রবর্তনের বিপরীতে যা এই উপায়ে দরকারী উপায়ে প্রকাশ করতে পারে।
মাস্টার

3

প্রথমত, ক্যাপচার ছাড়া ল্যাম্বদা ফাংশন পয়েন্টারে রূপান্তরিত হয়। সুতরাং তারা উদারতার কিছু ফর্ম সরবরাহ করে।

এখন ক্যাপচার সহ ল্যাম্বডাস কেন পয়েন্টারে রূপান্তরিত হয় না? কারণ ফাংশনটি অবশ্যই ল্যাম্বদার রাজ্যে অ্যাক্সেস করতে হবে, সুতরাং এই রাষ্ট্রটি একটি ফাংশন আর্গুমেন্ট হিসাবে উপস্থিত হওয়া প্রয়োজন।


আচ্ছা, ক্যাপচারগুলি ল্যাম্বডা নিজেই অংশ হওয়া উচিত, না? তারা যেমন একটি মধ্যে encapsulated হয় std::function<>
মাস্টার -

3

ব্যবহারকারীর কোড সহ নাম সংঘর্ষ এড়াতে।

এমনকি একই বাস্তবায়ন সহ দুটি লম্বাও বিভিন্ন ধরণের থাকবে। যা ঠিক আছে কারণ আমার মেমরির বিন্যাস সমান হলেও বস্তুর জন্য বিভিন্ন ধরণের থাকতে পারি।


এই জাতীয় ধরণের int (*)(Foo*, int, double)ব্যবহারকারীর কোডের সাথে নামের সংঘর্ষের ঝুঁকি নেই।
মাস্টার -

আপনার উদাহরণ খুব ভাল জেনারেল করে না। যদিও একটি ল্যাম্বডা এক্সপ্রেশনটি কেবল সিনট্যাক্স হয় এটি কিছু স্ট্রাক্ট বিশেষত ক্যাপচার ক্লজ সহ মূল্যায়ন করবে। এটিকে সুস্পষ্টভাবে নামকরণ করা গেলে ইতিমধ্যে বিদ্যমান স্ট্রাইকগুলির নাম সংঘর্ষ হতে পারে।
নিভিল

আবার, এই প্রশ্নটি ভাষা নকশা সম্পর্কে, সি ++ সম্পর্কে নয়। আমি অবশ্যই কোনও ভাষা সংজ্ঞায়িত করতে পারি যেখানে ল্যাম্বডার ধরণ কোনও ফর্মাল পয়েন্টার টাইপের সাথে ডেটা স্ট্রাকচার ধরণের চেয়ে বেশি সমান। সি ++ এ ফাংশন পয়েন্টার সিনট্যাক্স এবং সি-তে ডায়নামিক অ্যারে টাইপ সিনট্যাক্স প্রমাণ করে যে এটি সম্ভব। এবং এই প্রশ্নটি উত্থাপন করে, কেন ল্যাম্বডাস অনুরূপ পন্থা ব্যবহার করেননি?
মাস্টার -

4
না আপনি পারবেন না, পরিবর্তনশীল কার্য়িংয়ের কারণে (ক্যাপচারিং)। এটিকে কাজ করতে আপনার একটি ফাংশন এবং ডেটা উভয়ই প্রয়োজন।
অন্ধ

@ ব্লিনডি ওহ, হ্যাঁ, আমি পারি আমি ল্যাম্বডাকে দুটি পয়েন্টারযুক্ত একটি বস্তু হিসাবে সংজ্ঞায়িত করতে পারি, একটি ক্যাপচার অবজেক্টের জন্য এবং একটি কোডের জন্য। যেমন একটি ল্যাম্বডা বস্তু মান দ্বারা কাছাকাছি পাস করা সহজ হবে। অথবা আমি ক্যাপচার অবজেক্টের শুরুতে কোডের স্টাবের সাথে কৌশলগুলি টানতে পারি যা আসল ল্যাম্বদা কোডে ঝাঁপ দেওয়ার আগে তার নিজের ঠিকানা নেয়। এটি ল্যাম্বডা পয়েন্টারটিকে একক ঠিকানায় পরিণত করবে। পিপিসি প্ল্যাটফর্মটি প্রমাণিত হওয়ায় এটি অপ্রয়োজনীয়: পিপিসিতে, একটি ফাংশন পয়েন্টার আসলে পয়েন্টারগুলির একটি জুড়ি। সেই কারণে আপনি নিক্ষেপ না করতে পারেন void(*)(void)থেকে void*এবং স্ট্যান্ডার্ড সি / সি ++ ফিরে।
মাস্টার -
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.