2012-03-08 14 views
10

मैं विंडोज़ एपीआई फ़ंक्शंस को लपेटने की कोशिश कर रहा हूं ताकि त्रुटियों की जांच हो सके। जैसा कि मैंने पिछले SO प्रश्न में पाया है, मैं एपीआई फ़ंक्शन को कॉल करने के लिए टेम्पलेट फ़ंक्शन का उपयोग कर सकता हूं, और फिर सेट किए गए किसी भी त्रुटि को पुनर्प्राप्त करने के लिए GetLastError() पर कॉल कर सकता हूं। मैं इस त्रुटि को अपने Error कक्षा में भेज सकता हूं ताकि मुझे इसके बारे में जानकारी मिल सके। का प्रयोग के रूप में यह अद्भुत काम करता हैकंपाइल-टाइम पर जांचें यदि टेम्पलेट तर्क शून्य है

int WINAPI someFunc (int param1, BOOL param2); //body not accessible 

int main() 
{ 
    int ret = someFunc (5, true); //works normally 
    int ret2 = Wrap (someFunc, 5, true); //same as above, but I'll get a message if there's an error 
} 

इस प्रकार यह मैं कोड हो सकता है

template<typename TRet, typename... TArgs> 
TRet Wrap(TRet(WINAPI *api)(TArgs...), TArgs... args) 
{ 
    TRet ret = api(args...); 
    //check for errors 
    return ret; 
} 

:

यहाँ टेम्पलेट समारोह के लिए कोड है। हालांकि, एक संभावित समस्या है। समारोह

void WINAPI someFunc(); 

ले लो जब टेम्पलेट समारोह में इस subbing, यह इस प्रकार है:

void Wrap(void(WINAPI *api)()) 
{ 
    void ret = api(); //<-- ahem! Can't declare a variable of type void... 
    //check for errors 
    return ret; //<-- Can't return a value for void either 
} 

इस के आसपास पाने के लिए, मैं टेम्पलेट मैं कहाँ void साथ TRet प्रतिस्थापित का एक संस्करण बनाने की कोशिश की। दुर्भाग्यवश, यह वास्तव में केवल एक अस्पष्टता का कारण बनता है जिसका उपयोग करना है।

कि एक तरफ, मैं

if (strcmp (typeid (TRet).name(), "v") != 0) //typeid(void).name() == "v" 
{ 
    //do stuff with variable to return 
} 

else 
{ 
    //do stuff without returning anything 
} 

का उपयोग कर फिर भी कोशिश की, typeid एक क्रम तुलना है, इसलिए कोड अभी भी वजह से एक शून्य चर घोषित करने के लिए कोशिश कर रहा करने के लिए संकलन नहीं करता है, भले ही यह कभी नहीं होगा।

अगला, मैंने typeid के बजाय std::is_same <TRet, void>::value का उपयोग करने का प्रयास किया, लेकिन पता चला कि यह रनटाइम तुलना भी था।

इस बिंदु पर, मुझे नहीं पता कि आगे क्या प्रयास करना है। क्या संकलक को विश्वास करने की कोई संभावना है कि मुझे पता है कि मैं क्या कर रहा हूं ठीक है? मुझे Wrap पर एक अतिरिक्त तर्क संलग्न करने में कोई फर्क नहीं पड़ता, लेकिन मैं वास्तव में उसमें से कुछ भी प्राप्त नहीं कर सका।

मैं जीएनयू जी ++ 4.6.1, और विंडोज एक्सपी, साथ ही विंडोज 7 के साथ कोड :: ब्लॉक का उपयोग करता हूं। किसी भी मदद के लिए धन्यवाद, भले ही यह मुझे बता रहा हो कि मुझे केवल Wrap का उपयोग नहीं करना पड़ेगा शून्य के लिए काम करने वाले कार्यों के लिए।

+1

मुझे समझ में आया कि रिटर्न प्रकार को शून्य के रूप में क्यों काम नहीं किया गया है (वापसी प्रकारों पर असंबद्ध नहीं हो सकता है) लेकिन शून्य ** और ** अतिरिक्त पैरामीटर जोड़ने से काम करना चाहिए, क्या हुआ? आपको स्पष्ट प्रकारों के साथ आना पड़ सकता है। – Tod

+1

दिलचस्प सवाल। साइड नोट: स्थिर रूप से चेक न किए जाने के अलावा, 'टाइपिड' समाधान भी पोर्टेबल नहीं है। मानक 'type_info :: name()' द्वारा लौटाई गई स्ट्रिंग के बारे में कोई गारंटी नहीं देता है। – Thomas

+0

मैंने दोनों के संयोजन के बारे में नहीं सोचा था। मैं इसे आज़माउंगा। टाइपिड मुद्दे पर हेड-अप के लिए भी धन्यवाद। – chris

उत्तर

8

आप ठीक धुन विशेषज्ञताओं को एक सहायक वर्ग का उपयोग कर सकते हैं:

template <typename F> 
struct wrapper 
{}; 

template <typename Res, typename... Args> 
struct wrapper<Res(Args...)> 
{ 
    static Res wrap(Res (WINAPI *f)(Args...), Args&& args...) 
    { 
     Res r = f(std::forward<Args>(args)...); 
     // Blah blah 
     return r; 
    } 
}; 

template <typename... Args> 
struct wrapper<void(Args...)> 
{ 
    static void wrap(void (WINAPI *f)(Args...), Args&& args...) 
    { 
     f(std::forward<Args>(args)...); 
     // Blah blah 
    } 
}; 

अब, आप आवरण लिख सकते हैं:

template <typename Res, typename... Args> 
Res Wrap(Res (WINAPI *f)(Args...), Args&& args...) 
{ 
    return wrapper<Res(Args...)>::wrap(f, std::forward<Args>(args)...); 
} 

ध्यान दें कि यह और भी काम करता है जब Resvoid है। आपको return को फ़ंक्शन लौटने वाले शून्य में एक अभिव्यक्ति लौटने की अनुमति है।

सही प्रकार को Wrap(someFunc, 5, true) में, शून्य लौटने वाले फ़ंक्शंस के लिए भी कम किया जाता है।

+0

जानना अच्छा है, धन्यवाद। <> में एक प्रकार की आवश्यकता को समाप्त करता है (जिसे मैं बस सस्ता कर दूंगा और कहा था कि # vfrap लपेटें 'या कुछ)। मैं देखता हूं कि यह भी काम करता है या नहीं। किसी भी कारण से 'std :: forward' और' Args && args ... 'काम करना पसंद नहीं है, लेकिन winapi सी में है, इसलिए स्पष्ट रूप से (पिछला प्रश्न) आगे वैसे भी कोई लाभ नहीं प्रदान करता है। – chris

+0

कोई बात नहीं, आगे काम करने का फैसला किया। यह घर पर उपयोग किए जाने वाले संकलक और स्कूल में मेरे फ्लैश ड्राइव पर उपयोग करने के बीच एक विसंगति हो सकती है। – chris

+0

हां, यह पूरी तरह से काम करता है और एक ही वाक्यविन्यास रखता है। मुझे एक परिवर्तन करना था 'Args && args ...' को 'Args && ... args ...' में बदलना था। धन्यवाद। – chris

1

टिप्पणी से बढ़ावा देना समझने मैं क्यों शून्य के रूप में वापसी प्रकार विशेषज्ञता काम नहीं किया (वापसी प्रकार पर स्पष्ट करने नहीं कर सकता है), लेकिन शून्य के साथ विशेषज्ञता जवाब देने के लिए और जोड़ने एक अतिरिक्त पैरामीटर काम करना चाहिए, क्या हुआ? आपको स्पष्ट प्रकारों के साथ आना पड़ सकता है।

+0

स्वीकार्य उत्तर बदलने के लिए मैं क्षमा चाहता हूं, क्योंकि यह ठीक काम करता है, लेकिन अलेक्जेंड्रे सी का जवाब * सटीक * समान वाक्यविन्यास रखता है क्योंकि मैं किसी भी # डिफाईन स्टेटमेंट या उस तरह की चीजों के उपयोग के बिना पहले उपयोग कर रहा था। व्यापार बंद थोड़ा अतिरिक्त कोड है; पूरे रैपर की तुलना में कुछ भी नहीं। – chris

+0

कोई समस्या नहीं, मुझे लगता है कि स्वीकृत उत्तर वह व्यक्ति होना चाहिए जिसे आप किसी ऐसी स्थिति में देखना चाहते हैं जब वे खोज करते हैं। इसके अलावा तथ्य यह है कि अलेक्जेंड्रे का जवाब स्वचालित रूप से एक बग प्लस है। बस ऊपर उठना अच्छा है। – Tod

2

इस के आसपास जाने के लिए, मैंने टेम्पलेट का एक संस्करण बनाने का प्रयास किया जहां मैंने ट्रेट को शून्य से बदल दिया। दुर्भाग्यवश, यह वास्तव में केवल एक अस्पष्टता का कारण बनता है जिसका उपयोग करना है।

कि चाहिए काम करते हैं, मुझे विश्वास है, क्योंकि voidTRet की तुलना में अधिक विशिष्ट है, लेकिन जैसा कि आप बाहर बिंदु यह नहीं है। मुझे कुछ याद आ रहा है, लेकिन किसी भी दर पर, इससे कोई फर्क नहीं पड़ता, आप TRet ओवरलोड को चुनने से रोक सकते हैं।

template<typename TFun, typename... TArgs> 
auto Wrap(TFun api, TArgs&&... args) -> 
typename std::enable_if< 
    !std::is_void<typename std::result_of<TFun(TArgs...)>::type>::value, 
    typename std::result_of<TFun(TArgs...)>::type 
>::type 
{ 
    auto result = api(std::forward<TArgs&&>(args)...); 
    return result; 
} 

template<typename TFun, typename... TArgs> 
auto Wrap(TFun api, TArgs&&... args) -> 
typename std::enable_if< 
    std::is_void<typename std::result_of<TFun(TArgs...)>::type>::value, 
    typename std::result_of<TFun(TArgs...)>::type 
>::type 
{ 
    api(std::forward<TArgs&&>(args)...); 
} 

void WINAPI f1() 
{ 
} 

void WINAPI f2(double) 
{ 
} 

int WINAPI f3() 
{ 
    return 0; 
} 

int WINAPI f4(double) 
{ 
    return 0; 
} 

int main() { 
    Wrap(f1); 
    Wrap(f2, 0); 
    return Wrap(f3) * Wrap(f4, 0); 
} 

अद्यतन: पैरामीटर प्रकार के तर्क प्रकार से रूपांतरण के लिए अनुमति देने के लिए समायोजित।

+0

यह कोड ठीक काम करता है। हालांकि, मेरे दूसरे कोड से मिलान करने का प्रयास करते समय, मैंने पाया कि अस्पष्टता तब होती है जब फ़ंक्शन में कई पैरामीटर होते हैं। जब इसमें कोई पैरामीटर नहीं होता है, तो अस्पष्टता हटा दी जाती है। – chris

+0

@ क्रिसिस आह, ठीक है, तो यह भी मेरे लिए असफल हो जाता है। हालांकि, यह अधिभार को हटाकर आसानी से तय किया जाता है जिसका उपयोग नहीं किया जाना चाहिए, संपादित करेंगे। – hvd

+0

यह कुछ फैंसी काम है: पी मैंने कुछ बुनियादी गणित कार्यों के अलावा वास्तव में टेम्पलेट्स के साथ बहुत कुछ नहीं किया है, इसलिए मैं नए लोगों के बारे में सभी वाक्यविन्यास के साथ थोड़ा बेकार हूं।यह मेरे लिए भी ठीक काम करता है, और अब मुझे नहीं पता कि इसका किसका उपयोग है:/ – chris

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