লাম্বদার মধ্যেই কীভাবে একটি সি ++ ল্যাম্বডা ফাংশনের ঠিকানা পাবেন?


53

আমি কীভাবে নিজের মধ্যে ল্যাম্বডা ফাংশনের ঠিকানা পেতে পারি তা জানার চেষ্টা করছি। এখানে একটি নমুনা কোড রয়েছে:

[]() {
    std::cout << "Address of this lambda function is => " << ????
}();

আমি জানি যে আমি ল্যাম্বডাকে একটি ভেরিয়েবলে ক্যাপচার করতে পারি এবং ঠিকানাটি মুদ্রণ করতে পারি, তবে এই বেনাম ফাংশনটি সম্পাদন করার সময় আমি এটি জায়গায় করতে চাই।

এটি করার সহজ উপায় আছে?


24
এটি কি কেবল কৌতূহলের জন্য, বা আপনার কোনও সমাধান করার মতো অন্তর্নিহিত সমস্যা রয়েছে? যদি অন্তর্নিহিত সমস্যা থাকে তবে দয়া করে কোনও (আমাদের জন্য) অজানা সমস্যার সমাধানের একমাত্র সম্ভাব্য সমাধান সম্পর্কে জিজ্ঞাসা না করে সরাসরি এটি সম্পর্কে জিজ্ঞাসা করুন।
কিছু প্রোগ্রামার

41
... কার্যকরভাবে XY- সমস্যা নিশ্চিত করা।
iljarn

8
আপনি ম্যানুয়ালি লিখিত ফান্টেক্টর ক্লাসের সাথে ল্যাম্বডাকে প্রতিস্থাপন করতে পারেন এবং তারপরে ব্যবহার করতে পারেন this
হলিব্ল্যাকগেট

28
"নিজের মধ্যে একটি লাম্বা ফাংশনের ঠিকানা পাওয়া" সমাধান , এটি একটি সমাধান যা আপনি সঙ্কুচিতভাবে ফোকাস করেন। অন্যান্য সমাধান হতে পারে, সেগুলি আরও ভাল হতে পারে। তবে আমরা আপনাকে এটির সাহায্য করতে পারি না কারণ আসল সমস্যাটি কী তা আমরা জানি না। আপনি কী ঠিকানাটি ব্যবহার করবেন তা আমরা জানি না। আমি যা করার চেষ্টা করছি তা হ'ল আপনার আসল সমস্যাটি নিয়ে আপনাকে সহায়তা করা।
কিছু প্রোগ্রামার ড্যুড

8
@ সোপমপ্রগ্রামমারডুড আপনি যা বলছেন তার বেশিরভাগ বুদ্ধিমানের মধ্যে রয়েছে, " এক্স কীভাবে কীভাবে করা যায়?" জিজ্ঞাসা করে আমি কোনও সমস্যা দেখছি না । এক্স এখানে "নিজের থেকেই একটি ল্যাম্বডারের ঠিকানা পাচ্ছেন"। আপনি কী জানেন না যে ঠিকানাটির জন্য কী ব্যবহার করা হবে তা আপনি জানেন না এবং অন্য কারও মতামত অনুসারে "অজানা" সমাধান হতে পারে যা কোনও অজানা কোড বেজে সম্ভাব্য হতে পারে বা নাও পারে ( আমাদেরকে). আরও ভাল ধারণাটি হ'ল বর্ণিত সমস্যাটির উপরে ফোকাস করা। এটি হয় করণীয় বা তা হয় না। যদি তা হয় তবে কেমন হয় ? যদি তা না হয় তবে তা উল্লেখ করুন না এবং আইএমএইচও, আরও কিছু প্রস্তাব দেওয়া যেতে পারে।
কোড_ড্রেড

উত্তর:


32

এটি সরাসরি সম্ভব নয়।

তবে ল্যাম্বদা ক্যাপচারগুলি ক্লাস এবং কোনও বস্তুর ঠিকানা তার প্রথম সদস্যের ঠিকানার সাথে মিলে যায়। অতএব, আপনি যদি প্রথম ক্যাপচার হিসাবে মান হিসাবে একটি বস্তু ক্যাপচার করেন, তবে প্রথম ক্যাপচারের ঠিকানা ল্যাম্বডা অবজেক্টের ঠিকানার সাথে মিলে যায়:

int main() {
    int i = 0;
    auto f = [i]() { printf("%p\n", &i); };
    f();
    printf("%p\n", &f);
}

আউটপুট:

0x7ffe8b80d820
0x7ffe8b80d820

বিকল্পভাবে, আপনি একটি ডেকরেটর ডিজাইনের প্যাটার্ন ল্যাম্বদা তৈরি করতে পারেন যা ল্যাম্বডা ক্যাপচারের রেফারেন্সটিকে তার কল অপারেটরে পাস করে:

template<class F>
auto decorate(F f) {
    return [f](auto&&... args) mutable {
        f(f, std::forward<decltype(args)>(args)...);
    };
}

int main() {
    auto f = decorate([](auto& that) { printf("%p\n", &that); });
    f();
}

15
"কোনও বস্তুর ঠিকানা তার প্রথম সদস্যের ঠিকানার সাথে মিলে যায়" এটি কি কোথাও নির্দিষ্ট করা হয়েছে যে ক্যাপচারগুলি অর্ডার করা হয়েছে, বা কোনও অদৃশ্য সদস্য নেই?
এন। 'সর্বনাম' মি।

35
@ n.'pronouns'm। নাহ, এটি একটি বহনযোগ্য সমাধান। একটি ক্যাপচার বাস্তবায়ন প্যাডিং হ্রাস করতে সম্ভাব্য বৃহত্তম থেকে ছোট থেকে ছোটদের অর্ডার করতে পারে, স্ট্যান্ডার্ড স্পষ্টভাবে এটির জন্য অনুমতি দেয়।
ম্যাক্সিম এগারুশকিন

14
পুনরায়, "এটি একটি বহনযোগ্য সমাধান নয়।" অপরিবর্তিত আচরণের
সলোমন আস্তে আস্তে

1
@রুহোলা বলা শক্ত। "কোনও বস্তুর ঠিকানা তার প্রথম সদস্যের ঠিকানার সাথে মিলে যায়" স্ট্যান্ডার্ড-লেআউট প্রকারের জন্য সত্য । যদি আপনি পরীক্ষা করে থাকেন যে ল্যাম্বদার প্রকারটি ইউবি না ডেকে স্ট্যান্ডার্ড-লেআউট হয় তবে আপনি ইউবি ব্যয় না করে এটি করতে পারেন। ফলাফলের কোডটি বাস্তবায়ন-নির্ভর আচরণ করবে। প্রথমে প্রথমে এর বৈধতা পরীক্ষা না করেই কৌশলটি করা হয়, তবে ইউবি।
বেন ভয়েগট

4
আমি বিশ্বাস করি এটি অনির্দিষ্ট is 8.1.5.2, 15 অনুযায়ী: যখন ল্যাম্বডা-এক্সপ্রেশনটি মূল্যায়ন করা হয়, অনুলিপি দ্বারা ক্যাপচার করা সত্তাগুলি ফলাফলটি বন্ধ হওয়া অবজেক্টের প্রতিটি সম্পর্কিত অ-স্থিতিশীল ডেটা সদস্যকে সরাসরি-আরম্ভ করতে ব্যবহৃত হয় এবং সূচনা-ক্যাপচারের সাথে সম্পর্কিত অ স্থিতিশীল ডেটা সদস্যদের সংশ্লিষ্ট সূচনা (...) দ্বারা নির্দেশিত হিসাবে সূচনা করা হয়। (অ্যারে সদস্যদের জন্য, অ্যারের উপাদানগুলি ক্রমবর্ধমান সাবস্ক্রিপ্ট ক্রমে প্রত্যক্ষ-প্রাথমিককরণ করা হয়)) এই সূচনাটি অদৈর্ঘ্য ডেটা সদস্যদের হিসাবে ঘোষিত ( অদক্ষিত ) ক্রমে করা হয়।
এরবুর্থ বলেছেন মোনিকা পুনরায় ইনস্টল করুন 'ই

51

ল্যাম্বডায় কোনও ল্যাম্বডা অবজেক্টের ঠিকানা সরাসরি পাওয়ার কোনও উপায় নেই।

এখন, এটি যেমন হয় প্রায়শই দরকারী। সর্বাধিক সাধারণ ব্যবহারটি পুনরাবৃত্তি করার জন্য।

y_combinatorভাষায় যেখানে আপনি যেখানে সংজ্ঞায়িত যতক্ষণ নিজের সম্পর্কে কথা বলতে না পারে থেকে আসে। এটি খুব সহজেই প্রয়োগ করা যেতে পারে :

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( f, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( f, std::forward<Args>(args)... );
  }
};

এখন আপনি এটি করতে পারেন:

y_combinator{ [](auto& self) {
  std::cout<<"Address of this lambda function is => "<< &self;
} }();

এর বিভিন্নতা অন্তর্ভুক্ত করতে পারে:

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( *this, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( *this, std::forward<Args>(args)... );
  }
};

যেখানে প্রথম আর্গুমেন্ট হিসাবে selfপাস না করে পাস বলা যেতে পারে self

দ্বিতীয়টি বিশ্বাস করে সত্যিকারের y কম্বিনেটর (ওরফে ফিক্সড পয়েন্ট কম্বিনেটর) আমি বিশ্বাস করি। আপনি যা চান তা নির্ভর করে 'ল্যাম্বদার ঠিকানা' দ্বারা আপনি কী বোঝাতে চান তার উপর depends


3
বাহ, ওয়াই কম্বিনেটরগুলি লিস্প / জাভাস্ক্রিপ্ট / পাইথনের মতো ডায়নামিক-টাইপযুক্ত ভাষায় আপনার মাথাটি গুটিয়ে রাখতে যথেষ্ট শক্ত। আমি কখনও ভাবিনি যে আমি সি ++ তে একটি দেখতে পাব।
জেসন এস

13
আমি মনে করি আপনি যদি সি ++ এ এটি করেন তবে আপনি গ্রেপ্তারের জন্য প্রাপ্য
user541686

3
@ এসএমএল্টার্স অনিশ্চিত যদি Fমান বিন্যাস না হয় তবে তা y_combinatorহয় না, সুতরাং বুদ্ধিমান গ্যারান্টি সরবরাহ করা হয় না।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

2
@ শীর্ষস্থানীয় উত্তরটি কেবল তখনই কাজ করে যদি আপনার ল্যাম্বদা স্কোপে থাকে, এবং আপনি ভাঙ্গা ওভারহেড টাইপ করতে আপত্তি করেন না। তৃতীয় উত্তরটি হ'ল y সংযোজক। দ্বিতীয় উত্তরটি একটি ম্যানুয়াল ycombinator।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

2
@ kaz সি ++ 17 বৈশিষ্ট্য। 11/14 এ আপনি একটি মেক ফাংশন লিখবেন, যা এফ ছাড়িয়ে দেবে; 17-এ আপনি টেমপ্লেটের নামগুলি (এবং কখনও কখনও ছাড়ের গাইড) দিয়ে ছাড় করতে পারেন
ইয়াক্ক - অ্যাডাম নেভ্রামাউন্ট

25

এটি সমাধানের একটি উপায় হ'ল লিখিত ফান্টেক্টর ক্লাসের সাথে ল্যাম্বডা প্রতিস্থাপন করা। এটি ল্যাম্বডা মূলত হুডের নীচে রয়েছে।

তারপরে আপনি thisকোনও ভেরিয়েবলের জন্য ফান্টরকে কখনও না নিযুক্ত করে এমনকি ঠিকানাটি পেতে পারেন :

#include <iostream>

class Functor
{
public:
    void operator()() {
        std::cout << "Address of this functor is => " << this;
    }
};

int main()
{
    Functor()();
    return 0;
}

আউটপুট:

Address of this functor is => 0x7ffd4cd3a4df

এটির সুবিধাটি এটি 100% পোর্টেবল, এবং এর পক্ষে যুক্তিযুক্ত এবং বোঝার পক্ষে অত্যন্ত সহজ।


9
ফান্টর এমনকি struct { void operator()() { std::cout << "Address of this functor is => " << this << '\n'; } } f;
ল্যাম্বদার

-1

ল্যাম্বদা ক্যাপচার করুন:

std::function<void ()> fn = [&fn]() {
  std::cout << "My lambda is " << &fn << std::endl;
}

1
std::functionযদিও এখানে নমনীয়তার প্রয়োজন হয় না, এবং এটি যথেষ্ট ব্যয় করে আসে। এছাড়াও, সেই বস্তুটি অনুলিপি / মুভিং করা এটি ভেঙে দেবে।
উত্সাহীকারী

@ ডেডুপ্লিকেটর কেন এটির প্রয়োজন হয় না, যেহেতু এটিই কেবলমাত্র নমনীয় যা মানসম্পন্ন? অনুগ্রহ করে এমন একটি আনসার দিন যা কার্যকর হয় এবং এর পরে এসটিডি :: ফাংশনের প্রয়োজন হয় না।
ভিনসেন্ট ফোরমন্ড

এটি আরও ভাল এবং পরিষ্কার সমাধান বলে মনে হচ্ছে, যদি না ল্যাম্বদার ঠিকানা (যা নিজে নিজে খুব একটা বোঝায় না) না পাওয়া একমাত্র পয়েন্ট না হয়। একটি সাধারণ ব্যবহারের ক্ষেত্রে জন্য recursion উদ্দেশ্য যেমন দেখুন, নিজেই ভিতরে lambla এক্সেস আছে হবে: stackoverflow.com/questions/2067988/... যেখানে ফাংশন হিসাবে ঘোষণামূলক বিকল্প ব্যাপকভাবে একটি সমাধান হিসেবে :) স্বীকার করা হয়েছে
Abs

-6

এটি সম্ভব তবে অত্যন্ত প্ল্যাটফর্ম এবং সংকলক অপ্টিমাইজেশনের উপর নির্ভর করে।

আমি জানি যে বেশিরভাগ আর্কিটেকচারে, সেখানে নির্দেশ পয়েন্টার নামে একটি নিবন্ধ রয়েছে। এই সমাধানের বিষয়টি হ'ল আমরা ফাংশনের অভ্যন্তরে থাকা অবস্থায় এটি নিষ্কাশন করা।

এএমডি 64 তে নিম্নলিখিত কোডটি আপনাকে ফাংশনটির নিকটবর্তী ঠিকানাগুলি দেওয়া উচিত।

#include <iostream>

void* foo() {
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
      : "=a" (n));
    return n;
}

auto boo = [](){
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
       : "=a" (n));
    return n;
};

int main() {
    std::cout<<"foo"<<'\n'<<((void*)&foo)<<'\n'<<foo()<<std::endl;  
    std::cout<<"boo"<<'\n'<<((void*)&boo)<<'\n'<<boo()<<std::endl;
}

কিন্তু জিসিসি উপর উদাহরণস্বরূপ https://godbolt.org/z/dQXmHm সঙ্গে -O3অপ্টিমাইজেশান স্তর ফাংশন inlined করা হতে পারে।


2
আমি উঁচুতে পছন্দ করতে চাই, তবে আমি খুব একটা ছাই হয়ে যাইনি এবং এখানে কী ঘটছে তা বুঝতে পারি না। প্রক্রিয়াটি কীভাবে এটি কাজ করে তার কিছু ব্যাখ্যা সত্যই মূল্যবান হবে। এছাড়াও, " ফাংশনটির কাছাকাছি ঠিকানাগুলি" বলতে কী বোঝায় ? কোন ধ্রুবক / অপরিজ্ঞাত অফসেট আছে?
আরটি

2
@ majkrzak এটি "সত্য" উত্তর নয়, কারণ এটি সমস্ত পোস্টের মধ্যে সর্বনিম্ন বহনযোগ্য। ল্যাম্বদার ঠিকানাটি নিজেই ফেরত দেওয়ার গ্যারান্টি নেই।
বেনামে

এটি তাই বলেছে, তবে "এটি সম্ভব নয়" উত্তরটি মিথ্যা
asnwer

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