2014-10-16 12 views
12

कनवर्ट करना सबसे पहले, मैं दो वर्गों को परिभाषित करता हूं, जो एक-दूसरे से प्राप्त होते हैं।std :: function <void (व्युत्पन्न *)> को std :: function <void(Base*)>

class A { 
}; 
class B : public A { 
}; 

फिर, मैं एक समारोह के एक std::function<void(A*)> का उपयोग करता है की घोषणा: अंत में

void useCallback(std::function<void(A*)> myCallback);

, मैं का एक std::function प्राप्त एक अलग (लेकिन सैद्धांतिक रूप से संगत) कहीं और है कि मैं चाहते हैं से करने के लिए टाइप करें मेरे कॉलबैक फ़ंक्शन में उपयोग करें:

std::function<void(B*)> thisIsAGivenFunction; 

useCallback(thisIsAGivenFunction); 

मेरा कंपाइलर (क्लैंग ++) इस से इनकार करता है क्योंकिका प्रकारअपेक्षित प्रकार से मेल नहीं खाता है। लेकिन BA से विरासत में, यह thisIsAGivenFunction के लिए स्वीकार्य होने के लिए समझ में आता है।

क्या यह होना चाहिए? यदि नहीं, क्यों? और अगर यह होना चाहिए, तो मैं क्या गलत कर रहा हूँ?

+1

[सी ++ टेम्पलेट्स पॉलिमॉर्फिज्म] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2203388/c-templates-polymorphism) – Samuel

+3

यह डुप्लिकेट नहीं है, 'std :: function' ऐसे * रूपांतरण * का समर्थन करता है। लेकिन दूसरी तरफ, आप 'std :: function ' 'std :: function ' में कनवर्ट कर सकते हैं, क्योंकि 'ए *' पर चलने वाला फ़ंक्शन वही कर सकता है जब उसे 'बी *' का उदाहरण प्राप्त होता है, लेकिन दूसरी तरफ –

+0

आपकी समस्या का स्रोत 'std :: function' का उपयोग टेम्पलेट तर्क के रूप में' फ़ंक्शन 'को स्वीकार करने के बजाय कॉलबैक के रूप में कर रहा है। जब तक आपके पास ऐसा करने का कोई अच्छा कारण न हो, तब तक ऐसा न करें। – pmr

उत्तर

2

आप &Foo(Apple) पास नहीं कर सकते हैं जब कोई आपको Pear सहित यादृच्छिक पास कर सकता है।

+0

मुझे यह नहीं मिला। मेरे मामले में मेरा फ़ंक्शन 'उपयोग कॉलबैक' एक यादृच्छिक 'फल' की अपेक्षा करता है, और जब मैं इसे' पियर 'पास कर रहा हूं तो संकलक शिकायत करता है। – Ecco

+1

@Ecco। मुझे लगता है कि यह है कि आपका 'उपयोग कॉलबैक' एक 'फलों' ('नाशपाती' या 'ऐप्पल' हो सकता है) के साथ एक समारोह को कॉल करने की अपेक्षा करता है और आप इसे एक ऐसा कार्य दे रहे हैं जो कम से कम 'नाशपाती' की अपेक्षा करता है। – Niall

+2

निएल सही है। 'useCallback' आपके 'thisIsAGivenFunction' को' ए *' पॉइंटर को 'सी' ऑब्जेक्ट में दे सकता है। आपके फ़ंक्शन को ** सभी ** 'ए 'ऑब्जेक्ट्स स्वीकार करना है, सबसेट नहीं। वास्तव में – MSalters

14

मान लेते हैं कि अपने वर्ग पदानुक्रम थोड़ा बड़ा है दो:

struct A { int a; }; 
struct B : A { int b; }; 
struct C : A { int c; }; 

और आप नीचे की तरह कार्य होते हैं:

void takeA(A* ptr) 
{ 
    ptr->a = 1; 
} 

void takeB(B* ptr) 
{ 
    ptr->b = 2; 
} 

कि बीत रहा है, हम कह सकते हैं कि takeA किसी के साथ प्रतिदेय है A (या A स्वयं) से प्राप्त कक्षा का उदाहरण, और takeBकॉल करने योग्य सीएल के किसी भी उदाहरण के साथ गधा B:

takeA(new A); 
takeA(new B); 
takeA(new C); 

takeB(new B); 
// takeB(new A); // error! can't convert from A* to B* 
// takeB(new C); // error! can't convert from C* to B* 

अब, क्या std::function है, यह प्रतिदेय वस्तुओं के लिए एक आवरण है। यह संग्रहीत समारोह वस्तु के हस्ताक्षर के बारे में ज्यादा परवाह नहीं करता जब तक के रूप में है कि वस्तु अपनी std::function आवरण के मापदंडों के साथ प्रतिदेय है:

std::function<void(A*)> a; // can store anything that is callable with A* 
std::function<void(B*)> b; // can store anything that is callable with B* 

तुम क्या करने कोशिश कर रहे हैं, के लिए std::function<void(B*)> कन्वर्ट करने के लिए है std::function<void(A*)>। दूसरे शब्दों में, आप A* लेने वाले कार्यों के लिए रैपर क्लास के भीतर B* को कॉल करने योग्य ऑब्जेक्ट को स्टोर करना चाहते हैं। क्या A* से B* पर कोई अंतर्निहित रूपांतरण है? नहीं वहाँ नहीं है।

है यही कारण है कि एक के रूप में अच्छी तरह से वर्ग C का एक उदाहरण के लिए सूचक के साथ std::function<void(A*)> कॉल कर सकते हैं:

std::function<void(A*)> a = &takeA; 
a(new C); // valid! C* is forwarded to takeA, takeA is callable with C* 

तो std::function<void(A*)>लपेट सकता है प्रतिदेय वस्तु का एक उदाहरण केवल B* लेने आप यह कैसे उम्मीद करेंगे C* के साथ काम करने के लिए?:

std::function<void(B*)> b = &takeB; 
std::function<void(A*)> a = b; 
a(new C); // ooops, takeB tries to access ptr->b field, that C class doesn't have! 

सौभाग्य से, उपरोक्त कोड संकलित नहीं करता है।

हालांकि, इस तरह से विपरीत कर ठीक है:

std::function<void(A*)> a = &takeA; 
std::function<void(B*)> b = a; 
b(new B); // ok, interface is narrowed to B*, but takeA is still callable with B* 
2

यह काम करता है लेकिन विपरीत दिशा में:

struct A {}; 
struct B: A {}; 

struct X {}; 
struct Y: X {}; 

static X useCallback(std::function<X(B)> callback) { 
    return callback({}); 
} 

static Y cb(A) { 
    return {}; 
} 

int main() { 
    useCallback(cb); 
} 

कॉलबैक के हस्ताक्षर वाणी क्या यह करने के लिए पारित हो जाएगा और क्या करने के लिए है वापस आ जाओ विशिष्ट कॉलबैक कम विशिष्ट प्रकार ले सकता है यदि उनके बारे में ज्यादा परवाह नहीं है। इसी प्रकार यह अधिक विशिष्ट प्रकार वापस कर सकता है, अतिरिक्त जानकारी छीन ली जाएगी। Covariant बनाम contravariant प्रकार (सरलीकृत शब्द में इनपुट/आउटपुट) का संदर्भ लें।

+0

दाएं। Std :: function http://cpptruths.blogspot.com/2015/11/covariance-and-contravariance-in-c.html#function_contravariance में contravariance देखें – Sumant

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