2013-02-13 50 views
16

निम्नलिखित कोड कुलपति ++ 2012 के साथ संकलित किया गया था:सी ++ लैम्ब्डा फ़ंक्शन का डिफ़ॉल्ट कॉलिंग सम्मेलन क्या है?

void f1(void (__stdcall *)()) 
{} 

void f2(void (__cdecl *)()) 
{} 

void __cdecl h1() 
{} 

void __stdcall h2() 
{} 

int main() 
{ 
    f1(h1); // error C2664 
    f2(h2); // error C2664 

    f1([](){}); // OK 
    f2([](){}); // OK 

    auto fn = [](){}; 

    f1(fn); // OK 
    f2(fn); // OK 
} 

मुझे लगता है कि त्रुटियों सामान्य हैं अभी तक OKs असामान्य हैं।

तो, मेरे सवाल कर रहे हैं:

  1. एक सी ++ लैम्ब्डा समारोह के बुला सम्मेलन क्या है?

  2. कैसे एक सी ++ लैम्ब्डा समारोह के बुला सम्मेलन निर्दिष्ट करने के लिए?

  3. तो बुला सम्मेलन परिभाषित नहीं है, कैसे सही ढंग से एक लैम्ब्डा समारोह कहा जाता है के बाद ढेर अंतरिक्ष पुनरावृत्ति करने के लिए?

  4. क्या संकलक स्वचालित रूप से लैम्ब्डा फ़ंक्शन के कई संस्करण उत्पन्न करता है? निम्नलिखित छद्म कोड के रूप में अर्थात:

    [] __stdcall() {};

    [] __cdecl() {}; आदि

+3

इस प्रश्न को जोड़ने से उपयोगी लगता है: http://stackoverflow.com/questions/14169295/how-to-specify-vc11-lambda-calling-convention – jogojapan

+0

'f1'' __stdcall' का उपयोग कर रहा है लेकिन 'h1'' __cdecl'; यदि आप आसपास के लोगों को स्वैप करते हैं तो यह काम करता है? – congusbongus

+0

@Cong, त्रुटियों सामान्य हैं और OKs असामान्य हैं। – xmllmx

उत्तर

14

कुलपति ++ 2012 को संकलक राज्यविहीन lambdas के लिए स्वचालित रूप से बुला रूपांतरण (है कि कोई कब्जा वेरिएबल नहीं है) चुनें जब आप बदल "सूचक कार्य करने के लिए राज्यविहीन लैम्ब्डा"।

MSDN C++11 Features:

lambdas

[...] इसके अतिरिक्त विजुअल C++ विजुअल स्टूडियो 2012 में में, राज्यविहीन lambdas संकेत दिए गए कार्य करने के लिए परिवर्तनीय हैं। [...] (विजुअल स्टूडियो 2012 में विजुअल सी ++ इससे भी बेहतर है, क्योंकि हमने स्टेटसलेस लैम्ब्स को फ़ंक्शन पॉइंटर्स में परिवर्तनीय बना दिया है, जिसमें मनमाने ढंग से कॉलिंग कॉन्फ़्रेंस हैं। यह महत्वपूर्ण है जब आप एपीआई का उपयोग कर रहे हों जो __stdcall फ़ंक्शन जैसी चीजों की अपेक्षा करते हैं संकेत)


संपादित:।

एनबी: बुला रूपांतरण सी ++ स्टैंडर्ड से बाहर है, यह इस तरह मंच ABI (आवेदन द्विआधारी इंटरफेस के रूप में अन्य विनिर्देश पर निर्भर करता है)।

निम्नलिखित जवाब /FAs compiler option साथ उत्पादन विधानसभा कोड पर आधारित हैं। तो यह एक मात्र अनुमान है, और कृपया अधिक विवरण के लिए माइक्रोसॉफ्ट पूछना; पी

Q1। सी ++ लैम्ब्डा फ़ंक्शन का कॉलिंग सम्मेलन क्या है?

क्यू 3। यदि कॉलिंग सम्मेलन को परिभाषित नहीं किया गया है, तो लैम्ब्डा फ़ंक्शन कहने के बाद स्टैक स्पेस को सही तरीके से रीसायकल कैसे करें?

सबसे पहले, सी ++ लैम्ब्डा (-expression) एक समारोह (और न ही समारोह सूचक) नहीं है, तो आप एक फोन करने की तरह सामान्य कार्य लैम्ब्डा वस्तु को operator() कॉल कर सकते हैं। और उत्पादन विधानसभा कोड का कहना है कि कुलपति ++ 2012 __thiscall बुला रूपांतरण के साथ उत्पन्न लैम्ब्डा शरीर।

प्रश्न 2। सी ++ लैम्ब्डा फ़ंक्शन के कॉलिंग सम्मेलन को कैसे निर्दिष्ट करें?

AFAIK, वहाँ कोई रास्ता नहीं है। (यह केवल __thiscall हो सकता है)

Q4। क्या संकलक स्वचालित रूप से लैम्ब्डा फ़ंक्शन के कई संस्करण उत्पन्न करता है? यानी निम्नलिखित छद्म कोड के रूप में: [...]

शायद नहीं। कुलपति ++ 2012 लैम्ब्डा प्रकार केवल एक लैम्ब्डा शरीर कार्यान्वयन (void operator()()) प्रदान करता है, लेकिन कई प्रदान करता है "उपयोगकर्ता परिभाषित रूपांतरण कार्य करने के लिए प्रत्येक बुला रूपांतरण (void (__fastcall*)(void), void (__stdcall*)(void), और void (__cdecl*)(void) प्रकार के साथ ऑपरेटर वापसी समारोह सूचक) के लिए सूचक "।

यहाँ एक उदाहरण है;

// input source code 
auto lm = [](){ /*lambda-body*/ }; 

// reversed C++ code from VC++2012 output assembly code 
class lambda_UNIQUE_HASH { 
    void __thiscall operator()() { 
    /* lambda-body */ 
    } 
    // user-defined conversions 
    typedef void (__fastcall * fp_fastcall_t)(); 
    typedef void (__stdcall * fp_stdcall_t)(); 
    typedef void (__cdecl * fp_cdecl_t)(); 
    operator fp_fastcall_t() { ... } 
    operator fp_stdcall_t() { ... } 
    operator fp_cdecl_t() { ... } 
}; 
lambda_UNIQUE_HASH lm; 
+2

+1 (हालांकि उत्तर प्रश्न के सभी पहलुओं को शामिल नहीं करता है)। – jogojapan

+5

@jogojapan: यह सब कुछ बहुत कुछ शामिल करता है, क्योंकि एक लैम्ब्डा फ़ंक्शन अभी भी एक सदस्य कार्य है। और एक सदस्य समारोह वास्तव में कॉलिंग सम्मेलन नहीं है। '__cdecl' तरीके से नहीं। चूंकि कॉलिंग सम्मेलन प्लेटफार्म-विशिष्ट हैं, वैसे भी यह तय करने के लिए प्रत्येक मंच पर निर्भर करता है कि यह कैसे काम करता है। माइक्रोसॉफ्ट, एक * चौंकाने वाली * योग्यता की डिग्री प्रदर्शित करने, सबसे उपयोगी तरीके से फैसला किया। –

+0

@NicolBolas मैं क्या मतलब मुख्य रूप से है कि उद्धृत पाठ प्रश्न के भाग 2 के लिए एक स्पष्ट उत्तर देने के लिए प्रतीत नहीं होता है। ऊपर दिए गए विवरण में कहा गया है कि लैम्बडा सभी कॉलिंग सम्मेलनों में डिफ़ॉल्ट रूप से परिवर्तनीय हैं, लेकिन यह जरूरी नहीं है कि यदि कोई चाहें तो सम्मेलन निर्दिष्ट करने का कोई तरीका नहीं है। यह निश्चित रूप से वीसी-विशिष्ट वाक्यविन्यास होगा। (मुझे यकीन है कि अगर मैं सदस्य कार्यों के बारे में अपनी बात समझ में नहीं कर रहा हूँ lambdas हमेशा सदस्य कार्य हैं .. क्यों है।?) – jogojapan

3

एक राज्यविहीन लैम्ब्डा समारोह अभी भी एक वर्ग है, लेकिन एक वर्ग है कि परोक्ष एक समारोह सूचक में बदला जा सकता है।

सी ++ मानक कॉलिंग सम्मेलनों को कवर नहीं करता है, लेकिन ऐसा कोई कारण नहीं है कि एक स्टेटलेस लैम्ब्डा किसी भी कॉलिंग कन्वेंशन में एक रैपर नहीं बना सकता है, जिसके बाद लम्बाडा को फ़ंक्शन पॉइंटर में परिवर्तित किया जाता है।

एक उदाहरण के रूप में, हम ऐसा कर सकता है:

#include <iostream> 

void __cdecl h1() {} 
void __stdcall h2(){} 

// I'm lazy: 
typedef decltype(&h1) cdecl_nullary_ptr; 
typedef decltype(&h2) stdcall_nullary_ptr; 

template<typename StatelessNullaryFunctor> 
struct make_cdecl { 
    static void __cdecl do_it() { 
    StatelessNullaryFunctor()(); 
    } 
}; 
template<typename StatelessNullaryFunctor> 
struct make_stdcall { 
    static void __stdcall do_it() { 
    StatelessNullaryFunctor()(); 
    } 
}; 

struct test { 
    void operator()() const { hidden_implementation(); } 

    operator cdecl_nullary_ptr() const { 
    return &make_cdecl<test>::do_it; 
    } 
    operator stdcall_nullary_ptr() const { 
    return &make_stdcall<test>::do_it; 
    } 
}; 

जहां हमारे test राज्यविहीन nullary वर्ग दोनों एक cdecl और stdcall समारोह सूचक में परोक्ष परिवर्तित किया जा सकता है।

इसका महत्वपूर्ण हिस्सा यह है कि कॉलिंग सम्मेलन फ़ंक्शन पॉइंटर के प्रकार का हिस्सा है, इसलिए operator function_type जानता है कि कॉलिंग सम्मेलन का अनुरोध किया जा रहा है। और सही अग्रेषण के साथ, उपरोक्त भी कुशल हो सकता है।

+0

एक लैम्ब्डा फ़ंक्शन एक वर्ग है? – jogojapan

+4

@jogojapan: शायद यह कहना चाहिए, एक स्टेटलेस लैम्ब्डा अभी भी एक * ऑब्जेक्ट * है, लेकिन एक ऑब्जेक्ट जिसे फ़ंक्शन पॉइंटर में परिवर्तित किया जा सकता है। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^