2010-09-07 24 views
6

में प्रतिनिधि/फ़ंक्शन और इंटरफ़ेस को इंटरचेंज करना मैं एक फ़ंक्शन को परिभाषित करने में सक्षम होना चाहता हूं जो इंटरफ़ेस लेता है, लेकिन एक प्रतिनिधि या फ़ंक्शन के साथ पूरा किया जा सकता है जो समान कार्यक्षमता प्रदान करता है। उदाहरण के लिए, C++ मैं की तरह कुछ लिख सकते हैं:डी 2

typedef std::function<int (float)> toInt; 

void fun(toInt dg) { ... } 

struct impl1 { 
    int operator()(float x) { ... } 
}; 

int impl2(float x) { ... } 

और फिर या तो कार्यान्वयन का उपयोग कर इसे कहते हैं:

fun(impl1()); 
fun(&impl2); 

(यह float-> पूर्णांक रूपांतरण सिद्धांत को वर्णन करने के लिए सिर्फ एक सरल उदाहरण है, मेरी वास्तविक कार्यक्षमता नहीं)।

मैं डी में कुछ इसी तरह मेरे अनुभवहीन प्रयास इस तरह से चला गया प्राप्त करने के लिए करना चाहते हैं:

interface toInt { 
    int opCall(float); 
} 

void fun(toInt dg) { ... } 

int impl2(float x) { ... } 

fun(impl2); 

संकलक इस अंतिम पंक्ति है कि यह परोक्ष toInt प्रकार के impl2 परिवर्तित नहीं कर सकते पर शिकायत। मैं शायद मज़ेदार ओवरलोडेड कार्यान्वयन को जोड़ सकता हूं और रूपांतरण को स्पष्ट कर सकता हूं, लेकिन मैं सोच रहा था कि ऐसा करने का एक और अधिक सुरुचिपूर्ण और सामान्य तरीका है, जैसा उपरोक्त सी ++ उदाहरण में है।

उत्तर

5

he_the_great यह मूल रूप से सही है, लेकिन निम्न छोटा सा परिवर्तन यह रूप में अच्छी तरह opCall सक्षम संरचनाओं/वर्गों के साथ काम कर देगा।

import std.conv; 
import std.stdio; 
import std.traits; 

void fun (T) (float value, T pred) 
if (__traits(compiles, pred(value)) && is(ReturnType!pred : int)) 
{ 
    writefln("pred(%f) -> %s", value, pred(value)); 
} 

struct impl1 { 
    int opCall (float f) { 
     return to!int(f); 
    } 
} 

int impl2 (float f) { 
    return to!int(f); 
} 

void main() { 
    impl1 x; 
    fun(1.0, x); 

    fun(2.0, &impl2); 

    fun(3.0, (float f){ return to!int(f); }); 
}
+1

नौसिखिया की मदद के लिए धन्यवाद :) यह सबसे व्यावहारिक समाधान की तरह लगता है। यह कॉलर के परिप्रेक्ष्य से संकेत की अतिरिक्त परत जोड़ता है: आप केवल f (x) की बजाय मजेदार (x, f) को कॉल कर रहे हैं, जैसा कि std :: function के साथ होगा। मैंने std.curry के साथ इसे ठीक करने की कोशिश की! (मज़ेदार() के लिए पैरामीटर ऑर्डर को उलटाना और उपनाम करी का उपयोग करना! (मजेदार, एक्स) fun1; fun1 (0.0);), लेकिन कंपाइलर खुश नहीं है: त्रुटि: "टेम्पलेट tst.main.curry! (मजेदार, एक्स) .curry (टी) अगर (है (टाइप (मजेदार (तर्क, T.init)))) किसी भी समारोह टेम्पलेट घोषणा से मेल नहीं खाता "(टेम्पलेट तर्क को कम नहीं कर सकता)। – Eitan

+0

मैं इसे [कोड] उपनाम करी का उपयोग करके काम करने में सक्षम था! (मजेदार! Impl1, x) funX; funX (4.4); [/ कोड] यहां मुद्दा यह है कि 'करी' से पहले टेम्पलेट 'मज़े' को फ़ंक्शन 'मजेदार' में विस्तारित करने की आवश्यकता है, इसके बारे में जानता है कि इसके साथ कैसे काम करना है। यह शायद एक आम पर्याप्त परिदृश्य है कि इसे stdlib में जोड़ा जाना चाहिए, हालांकि। बेशक आप इसे [कोड] उपनाम करी का उपयोग करके अधिक सामान्य बना सकते हैं! (मजेदार! (टाइपोफ (एक्स)), एक्स) funX; [/ कोड] ताकि आपको उपभोक्ता को करी करने के लिए पूरे, संभवतः जटिल, x का प्रकार दोहराना पड़े। –

3

डी फ़ंक्शंस और प्रतिनिधियों का एक भेद बनाता है क्योंकि प्रतिनिधि केवल फ़ंक्शन के सूचक के मुकाबले बड़े होते हैं। तो ऐसा कोई प्रकार नहीं है जो दोनों के लिए काम करेगा। फोबोस में कार्यों के लिए एक रैपर जोड़ने की चर्चा हुई है (जैसा कि डिस्मिचा बताता है, यह std.functional.toDelegate है)। आप टेम्पलेट्स का उपयोग कर सकते (मैं अगर यह काम करता है की जाँच करने के लिए नवीनतम संकलक करने के लिए पहुँच नहीं है)

import std.traits; 
import std.conv; 

void fun(F)(F dg) if(isSomeFunction!(F) && __traits(compiles, int a = dg(35.6)) 
{ } 

struct someStruct { 
    int operator(float x) { return to!int(x); } 
}; 

int impl2(float x) { return to!int(x); } 


void main() { 
    someStruct impl1; 
    fun(&impl1.operator); 
    fun(&impl2); 
} 
3

he_the_great से उल्लेख किया है, टेम्पलेट्स ज्यादातर मामलों में सबसे अच्छा समाधान कर रहे हैं। (यह waht std :: फ़ंक्शन किसी भी तरह से कर रहा है।) यदि आप टेम्पलेट्स का उपयोग नहीं करना चाहते/नहीं कर सकते हैं, तो std.functional में देखें। आपको toDelegate() नामक एक फ़ंक्शन मिलेगा, जो किसी फ़ंक्शन पॉइंटर को प्रतिनिधि में बदलने के लिए कुछ स्नीकी जादू का उपयोग करता है। फिर आप यह कर सकते हैं:

import std.functional; 

struct Impl1 { 
    int doConversion(float x) { return cast(int) x; } 
} 

int impl2(float x) { return cast(int) x; } 

void fun(int delegate(float) dg) {} 

void main() { 
    Impl1 impl1; 
    fun(&impl1.doConversion); 
    fun(toDelegate(&impl2)); 
} 

तुम भी कुछ के बराबर लिख सकता है सी ++ के std::function है, जो की संभावना तुच्छ होगा। वास्तव में, मैं इसे यहाँ करूँगा। नोट, हालांकि यह ref या out पैरामीटर सही ढंग से संभाल नहीं करता है या संकलक बग के कारण अभी वापस आता है।

import std.traits; 

interface Function(ReturnType, Args...) { 
    ReturnType opCall(Args); 
} 

class FunctionImpl(C) : Function!(ReturnType!C, ParameterTypeTuple!C) { 
    C callable; 

    this(C callable) { 
     this.callable = callable; 
    } 

    ReturnType!C opCall(ParameterTypeTuple!C args) { 
     return callable(args); 
    } 
} 

/**Convenience function for creating a Function object w/o explicitly 
    specifying types 
*/ 
FunctionImpl!C functionObject(C)(C callable) { 
    return new typeof(return)(callable); 
} 

// Test function. 
uint inc(uint num) { 
    return num + 1; 
} 

// Test it out. 
void main() { 
    auto myFun = functionObject(&inc); 
    assert(myFun(1) == 2); 
}