एक लैम्ब्डा फ़ंक्शन को अधिभारित करें


14

एक साधारण स्थानीय लैम्ब्डा फ़ंक्शन को कैसे अधिभारित करें?

मूल समस्या का SSE:

#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'

कृपया उपयोगकर्ता इनपुट की जाँच न करें, यह एक SSE है।


7
लैम्ब्डा फ़ंक्शन नहीं हैं, वे ऑब्जेक्ट हैं इसलिए ओवरलोडिंग उन पर कभी भी लागू नहीं होती है। translateकेवल स्थानीय चर हैं जो समान नाम का पुन: उपयोग नहीं कर सकते हैं।
20:78 पर user7860670

2
संबंधित /
डुबकी

जवाबों:


10

नहीं, आप लंबोदर को अधिभार नहीं दे सकते!

लैम्ब्डा गुमनाम फंक्शंस (यानी अनाम फ़ंक्शन ऑब्जेक्ट्स) हैं, और सरल फ़ंक्शन नहीं हैं। इसलिए, उन वस्तुओं को ओवरलोड करना संभव नहीं है। आप मूल रूप से जो करने की कोशिश कर रहे हैं वह लगभग है

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एक ही शाखा है, जो संकलन के समय सही है

मतलब संभव समाधान हैं:

  • एक एकल varabe टेम्पलेट लैम्ब्डा। या
  • एक सामान्य लैम्ब्डा और चेक के decltype लिए उपयोग किए जाने वाले पैरामीटर के प्रकार का पता लगाएं if constexpr। (क्रेडिट @NathanOliver )

Varabe टेम्पलेट का उपयोग करके आप कुछ ऐसा कर सकते हैं। ( ऑनलाइन एक लाइव डेमो देखें )

#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। दूसरे, एक चर टेम्पलेट का उपयोग क्यों करें? तुम बस लैम्ब्डा सामान्य कर सकता है और अपने checls बन जाएगा if constexpr (std::is_same_v<decltype(idx), int>)औरelse if constexpr (std::is_same_v<decltype(idx), char>)
NathanOliver

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;
}

एक मिनट रुकिए, आप लंबोदर सिंटैक्स को अच्छा कह रहे हैं ??
user7860670

1
@VTT यह अच्छा है कि वाक्यविन्यास बहुत अच्छा है। कुछ और प्राचीन चीजों की तुलना में यह बहुत बुरा नहीं है
idclev 463035818

5

इसलिए नामों को ओवरलोड करने के नियम केवल कुछ प्रकार के फ़ंक्शन नामों (दोनों निशुल्क और विधियों) के लुकअप पर लागू होते हैं

लैम्ब्डा फ़ंक्शन नहीं हैं, वे एक फ़ंक्शन-कॉल ऑपरेटर के साथ ऑब्जेक्ट हैं। इसलिए दो अलग-अलग मेमनों के बीच ओवरलोडिंग नहीं हो सकती है।

अब, आप फंक्शन ऑब्जेक्ट्स के साथ काम करने के लिए ओवरलोड रिज़ॉल्यूशन प्राप्त कर सकते हैं, लेकिन केवल एक ऑब्जेक्ट के दायरे में। और फिर अगर एक से अधिक है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 दोनों में संभव है लेकिन इसके लिए अधिक काम करने की आवश्यकता है और कम सुरुचिपूर्ण है। एक बार जब आप इस समस्या से अवगत हो जाते हैं, तो एक समाधान खोजना जो मेल खाता है कि C ++ सुविधाओं के तरीके में आपका विशेष संकलक क्या समर्थन करता है, कठिन नहीं होना चाहिए।


जैसा कि मैं समझता हूं कि प्रत्येक "अतिभारित" लैम्डा के पास स्वयं का कैप्चर ब्लॉक है, अर्थात उन लैम्ब्डा कुछ भी साझा नहीं करते हैं (और शायद सीपीयू समय को एक ही डेटा पर कैप्चर करते हुए बर्बाद कर देते हैं)। कोई भी मौका C ++ मानक को सुधारने के लिए कुछ होगा? या केवल विकल्प variadic generic lamda+ if constexprअलग कॉल करने के लिए है?
सीएम

@ सीएम स्टैक ओवरफ्लो पर एक प्रश्न पूछने के लिए, कृपया अपने शीर्ष दाईं ओर [प्रश्न पूछें] बटन दबाएं, न कि [टिप्पणी जोड़ें] बटन। धन्यवाद!
यक्क - एडम नेवरामॉन्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.