একটি ল্যাম্বদা ফাংশন ওভারলোড করুন


14

কিভাবে একটি সাধারণ স্থানীয় ল্যাম্বদা ফাংশন ওভারলোড করবেন?

মূল সমস্যার এসএসই:

#include <iostream>
#include <map>

void read()
{
    static std::string line;
    std::getline(std::cin, line);

    auto translate = [](int idx)
    {
        constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
        return table[idx];
    };

    auto translate = [](char c)
    {
        std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3},
                                             {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
        return table[c];
    };

    int r = translate(static_cast<int>(line[0]));
    int c = translate(static_cast<char>(line[1]));
    std::cout << r << c << std::endl;
}

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

ত্রুটি বার্তা

error: conflicting declaration 'auto translate'
note: previous declaration as 'read()::<lambda(int)> translate'

ব্যবহারকারীর ইনপুট পরীক্ষা না করে দয়া করে মনে করবেন না, এটি একটি এসএসই।


7
লাম্বডাস কোনও ফাংশন নয়, এগুলি এমন বস্তু যাতে ওভারলোডিং তাদের ক্ষেত্রে প্রযোজ্য না। translateকেবল স্থানীয় ভেরিয়েবল যা একই নামটি পুনরায় ব্যবহার করতে পারে না।
ব্যবহারকারীর 7860670

2
সংশ্লিষ্ট / প্রতারিত: stackoverflow.com/questions/32475576/...
NathanOliver

উত্তর:


10

না, আপনি ল্যাম্বডাকে ওভারলোড করতে পারবেন না!

ল্যাম্বডাস বেনামে ফান্টেক্টর (অর্থাত্ নামবিহীন ফাংশন অবজেক্টস), এবং সাধারণ ফাংশন নয়। অতএব, objects অবজেক্টগুলি ওভারলোড করা সম্ভব নয়। আপনি মূলত যা করার চেষ্টা করছেন তা প্রায়

struct <some_name>
{
    int operator()(int idx) const
    {
        return {}; // some int
    }
}translate; // >>> variable name

struct <some_name>
{
    int operator()(char idx) const
    {
        return {}; // some int
    }
}translate; // >>> variable name

যা সম্ভব নয়, কারণ একই পরিবর্তনশীল নামটি C ++ এ পুনরায় ব্যবহার করা যায় না।


যাইহোক, আমাদের রয়েছে if constexprযার দ্বারা কেউ একমাত্র শাখাটি ইনস্ট্যান্ট করতে পারে যা সংকলনের সময় সত্য।

সম্ভাব্য সমাধানগুলি হ'ল অর্থ:

  • একটি একক ভেরিয়েব টেম্পলেট লাম্বদা । অথবা
  • একটি জেনেরিক ল্যাম্বদা এবং চেকটিরdecltype জন্য প্যারামিটারের ধরণটি খুঁজে বার করুন credif constexpr (ক্রেডিটগুলি @ নাথানঅলিভার )

ভেরাবেব টেম্পলেট ব্যবহার করে আপনি এর মতো কিছু করতে পারেন। ( অনলাইন লাইভ ডেমো দেখুন )

#include <type_traits> // std::is_same_v

template<typename T>
constexpr auto translate = [](T idx) 
{
    if constexpr (std::is_same_v<T, int>)
    {
        constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
        return table[idx];
    }
    else if constexpr (std::is_same_v<T, char>)
    {
        std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}, {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
        return table[idx];
    }
};

এবং এটি পছন্দ করুন

int r = translate<int>(line[0]);
int c = translate<char>(line[1]);

জেনেরিক ল্যাম্বদা ব্যবহার করে (যেহেতু ), হবে: ( অনলাইনে একটি লাইভ ডেমো দেখুন )

#include <type_traits> // std::is_same_v

constexpr auto translate = [](auto idx) 
{
    if constexpr (std::is_same_v<decltype(idx), int>)
    {
        constexpr static int table[8]{ 7,6,5,4,3,2,1,0 };
        return table[idx];
    }
    else if constexpr (std::is_same_v<decltype(idx), char>)
    {
        std::map<char, int> table{ {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}, {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
        return table[idx];
    }
};

এবং এখন যেমন করে ল্যাম্বডাকে কল করুন:

int r = translate(static_cast<int>(line[0]));
int c = translate(static_cast<char>(line[1]));

3
আমি এই আশ্চর্যজনক খুঁজে পেয়েছি
স্নোপি

1
প্রথমত, আপনার else ifপ্রয়োজন else if constexpr। দ্বিতীয়ত, কেন একটি ভেরিয়েবল টেম্পলেট ব্যবহার করবেন? আপনি কেবল ল্যাম্বডাকে জেনেরিক তৈরি করতে পারেন এবং আপনার চেকগুলি হয়ে উঠবে if constexpr (std::is_same_v<decltype(idx), int>)এবংelse if constexpr (std::is_same_v<decltype(idx), char>)
নাথান অলিভার

6

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

তবে আপনি একটি ওভারলোডেড দিয়ে ফান্টারের সংজ্ঞা দিতে পারেন operator()। এটি সম্ভব হলে ল্যাম্বডাসের কাছ থেকে হুবহু কী পাবেন। আপনি কেবল ক্ষুদ্র বাক্য গঠন পেতে পারেন না।

কিছুটা এইরকম:

void read()
{
    static std::string line;

    struct translator {
          int operator()(int idx) { /* ... */ }
          int operator()(char x)  { /* ... */ }
    };
    translator translate;


    std::getline(std::cin, line);

    int r = translate(static_cast<int>(line[0]));
    int c = translate(static_cast<char>(line[1]));

    std::cout << r << c << std::endl;
}

এক মিনিট অপেক্ষা করুন, আপনি ল্যাম্বদা সিনট্যাক্সকে সুন্দর বলছেন ??
ব্যবহারকারীর 7860670

1
@ ভিটিটি এটি খুব সুন্দর যে সিনট্যাক্সটি সংশ্লেষিত হয়। আরও কিছু প্রাচীন জিনিসের তুলনায় এটি খুব খারাপ নয়
idclev 463035818

5

সুতরাং নামগুলি ওভারলোড করার নিয়মগুলি কেবলমাত্র ফাংশন নামের (ফ্রি এবং পদ্ধতি উভয়) নির্দিষ্ট ধরণের প্রযোজ্য ক্ষেত্রে প্রযোজ্য

লাম্বডাস ফাংশন নয়, এগুলি ফাংশন-কল অপারেটর সহ বস্তু। সুতরাং ওভারলোডিং দুটি পৃথক ল্যাম্বডাসের মধ্যে ঘটতে পারে না।

এখন, আপনি ফাংশন অবজেক্টের সাথে কাজ করতে ওভারলোড রেজোলিউশন পেতে পারেন তবে কেবলমাত্র একটি একক অবজেক্টের মধ্যে within এবং তারপরে যদি একের বেশি হয় তবে operator()ওভারলোড রেজোলিউশন তাদের মধ্যে চয়ন করতে পারে।

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

template<class...Fs>
struct overloaded : Fs... {
  using Fs::operator()...;
};

এবং একটি ছাড়ের গাইড:

template<class...Fs>
overloaded(Fs...) -> overloaded<Fs...>;

এই দুটি দিয়ে আমরা দুটি ল্যাম্বডাস ওভারলোড করতে পারি:

static std::string line;
std::getline(std::cin, line);

auto translate_int = [](int idx){
    constexpr static int table[8] {7,6,5,4,3,2,1,0};
    return table[idx];
};

auto translate_char = [](char c) {
    std::map<char, int> table { {'a', 0}, {'b', 1}, {'c', 2}, {'d', 3},
                                {'e', 4}, {'f', 5}, {'g', 6}, {'h', 7} };
    return table[c];
};
auto translate = overloaded{ translate_int, translate_char };

int r = translate(static_cast<int>(line[0]));
int c = translate(static_cast<char>(line[1]));

এবং সম্পন্ন।

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


যেহেতু আমি প্রতিটি "ওভারলোডেড" লামডাকে বুঝতে পারি তার নিজস্ব ক্যাপচার ব্লক রয়েছে, অর্থাত্ সেই ল্যাম্বডাসগুলি কিছু ভাগ করে না (এবং সম্ভবত সিপিইউ সময় একই সাথে একই সাথে ডেটা ক্যাপচার করে দেয়)। কোনও সুযোগ সি ++ স্ট্যান্ডার্ডের কিছু সংশোধন করার আছে? অথবা শুধুমাত্র বিকল্প variadic generic lamda+ + if constexprপৃথক কল?
সিএম

@ সিএম স্ট্যাক ওভারফ্লো সম্পর্কে একটি প্রশ্ন জিজ্ঞাসা করতে, দয়া করে [প্রশ্ন জিজ্ঞাসা করুন] বোতামটি আপনার ডানদিকে ডানদিকে চাপুন, [মন্তব্য যুক্ত করুন] বোতামটি নয়। ধন্যবাদ!
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.