2010-12-26 9 views
6

लौटाता है, मैंने इस पर विभिन्न प्राधिकरणों को पढ़ा है, इसमें Dewhurst शामिल हैं और फिर भी इस असाधारण सरल प्रश्न के साथ कहीं भी नहीं पहुंच पाए हैं।SFINAE और यह पता लगाने पर कि कोई C++ फ़ंक्शन ऑब्जेक्ट शून्य

मुझे क्या करना चाहते हैं कॉल है एक सी ++ function object, (मूल रूप से, कुछ भी आप कॉल कर सकते हैं, एक शुद्ध समारोह या के साथ एक कक्षा()), और इसके मूल्य वापस, अगर है कि शून्य नहीं है, या " सच "अन्यथा।

using std: 

struct Foo { 
    void operator()() { cout << "Foo/"l; } 
}; 
struct Bar { 
    bool operator()() { cout << "Bar/"; return true; } 
}; 

Foo foo; 
Bar bar; 
bool baz() { cout << "baz/"; return true; } 
void bang() { cout << "bang/"; } 

const char* print(bool b) { cout << b ? "true/" : "false/"; } 

template <typename Functor> bool magicCallFunction(Functor f) { 
    return true; // Lots of template magic occurs here 
       // that results in the functor being called. 
} 

int main(int argc, char** argv) { 
    print(magicCallFunction(foo)); 
    print(magicCallFunction(bar)); 
    print(magicCallFunction(baz)); 
    print(magicCallFunction(bang)); 
    printf("\n"); 
} 
// Results: Foo/true/Bar/true/baz/true/bang/true 

अद्यतन

धन्यवाद विचारों और विचारों के लिए!

इस के आधार पर, मैं वास्तव में मेरे सारे templating एक स्तर ऊपर लाने का फैसला किया - तो बजाय मेरे पास है:

bool eval(bool (*f)()) { return (*f)(); } 

bool eval(void (*f)()) { (*f)(); return true; } 

template <typename Type> 
bool eval(Type* obj, bool (Type::*method)()) { return (obj->*method)(); } 

template <typename Type> 
bool eval(Type* obj, void (Type::*method)()) { (obj->*method)(); return true; } 

और सामान्य वर्गों के आसपास विभिन्न वस्तुओं और विधियों ले जाने के लिए। कोड के लिए श्रीमान को धन्यवाद, जिसने मुझे उस दिशा में धक्का दिया!

उत्तर

1

प्रिंट (शून्य) का ओवरलोडेड नो-ऑप संस्करण लागू करना आसान नहीं होगा?

अहह ठीक है। फ़ंक्शन टेम्पलेट्स और ओवरलोडिंग आसानी से रनटाइम पर इसे संभालेंगे।

यदि आप #if मैक्रोज़ या स्थैतिक-संकलन-समय-आवेषण के साथ उपयोग के लिए संकलन समय पर इसे संभालना चाहते हैं तो यह कुछ हद तक चिपचिपा हो जाता है। । मुझे पता है, मैं अपग्रेड करने की आवश्यकता -

((जीसीसी) 3.4.4 & 4.0.1 के तहत परीक्षण किया गया:

लेकिन जब से तुम केवल पूर्व चाहते हैं, मैं एक प्रारंभिक बिंदु के रूप कुछ इस तरह का सुझाव दे सकते !)

#include <iostream> 
using namespace std; 

struct Foo { 
    void operator()() {} 
}; 
struct Bar { 
    bool operator()() { return false; } 
}; 
Foo foo; 
Bar bar; 
bool baz() { return false; } 
void bang() {} 


struct IsVoid 
{ 
    typedef char YES[1]; 
    typedef char NO[2]; 

     /* Testing functions for void return value. */ 

    template <typename T> 
    static IsVoid::NO & testFunction(T (*f)()); 

    static IsVoid::YES & testFunction(void (*f)()); 

    static IsVoid::NO & testFunction(...); 

     /* Testing Objects for "void operator()()" void return value. */ 

    template <typename C, void (C::*)()> 
    struct hasOperatorMethodStruct { }; 

    template <typename C> 
    static YES & testMethod(hasOperatorMethodStruct<C, &C::operator()> *); 

    template <typename C> 
    static NO & testMethod(...); 


     /* Function object method to call to perform test. */ 
    template <typename T> 
    bool operator() (T & t) 
    { 
    return ( (sizeof(IsVoid::testFunction(t)) == sizeof(IsVoid::YES)) 
      || (sizeof(IsVoid::testMethod<T>(0)) == sizeof(IsVoid::YES))); 
    } 
}; 


#define BOUT(X) cout << # X " = " << boolToString(X) << endl; 

const char * boolToString(int theBool) 
{ 
    switch (theBool) 
    { 
    case true: return "true"; 
    case false: return "false"; 
    default:  return "unknownvalue"; 
    } 
} 

int main() 
{ 
    IsVoid i; 

    BOUT(IsVoid()(foo)); 
    BOUT(IsVoid()(bar)); 
    BOUT(IsVoid()(baz)); 
    BOUT(IsVoid()(bang)); 
    cout << endl; 

    BOUT(i(foo)); 
    BOUT(i(bar)); 
    BOUT(i(baz)); 
    BOUT(i(bang)); 
} 



ठीक है, मैं इस समस्या के और अधिक देखने लगते हैं।

हम इस की तर्ज पर कुछ कर सकते हैं जबकि:

#include <iostream> 
using namespace std; 

struct FooA { 
    void operator()() {} 
}; 
struct FooB { 
    bool operator()() { return false; } 
}; 
struct FooC { 
    int operator()() { return 17; } 
}; 
struct FooD { 
    double operator()() { return 3.14159; } 
}; 
FooA fooA; 
FooB fooB; 
FooC fooC; 
FooD fooD; 

void barA() {} 
bool barB() { return false; } 
int barC() { return 17; } 
double barD() { return 3.14159; } 


namespace N 
{ 
     /* Functions */ 

    template <typename R> 
    R run(R (*f)()) { return (*f)(); } 

    bool run(void (*f)()) { (*f)(); return true; } 


     /* Methods */ 

    template <typename T, typename R> 
    R run(T & t, R (T::*f)()) { return (t .* f)(); } 

    template <typename T> 
    bool run(T & t, void (T::*f)()) { (t .* f)(); return true; } 
}; 


#define SHOW(X) cout << # X " = " << (X) << endl; 
#define BOUT(X) cout << # X " = " << boolToString(X) << endl; 

const char * boolToString(int theBool) 
{ 
    switch (theBool) 
    { 
    case true: return "true"; 
    case false: return "false"; 
    default:  return "unknownvalue"; 
    } 
} 


int main() 
{ 
    SHOW(N::run(barA)); 
    BOUT(N::run(barA)); 
    SHOW(N::run(barB)); 
    BOUT(N::run(barB)); 
    SHOW(N::run(barC)); 
    SHOW(N::run(barD)); 
    cout << endl; 

    SHOW(N::run(fooA,&FooA::operator())); 
    BOUT(N::run(fooA,&FooA::operator())); 
    SHOW(N::run(fooB,&FooB::operator())); 
    BOUT(N::run(fooB,&FooB::operator())); 
    SHOW(N::run(fooC,&FooC::operator())); 
    SHOW(N::run(fooD,&FooD::operator())); 
} 

तुम अब भी है कि एक तर्क के रूप & क्लास :: ऑपरेटर() को खिलाने के लिए बुरा जरूरत होती है।


अंततः, हम तय कर सकते हैं, जबकि वस्तु की ऑपरेटर() विधि एक शून्य रिटर्न या नहीं, हम आम तौर पर अधिभार वापसी प्रकार के आधार पर नहीं कर सकते।

हम टेम्पलेट विशेषज्ञता के माध्यम से उस ओवरलोडिंग सीमा के आसपास हो सकते हैं। लेकिन फिर हम इस बदसूरतता में आते हैं जिसमें हमें अभी भी प्रकार निर्दिष्ट करने की आवश्यकता है ... विशेष रूप से वापसी का प्रकार! या तो मैन्युअल रूप से, या उपयुक्त तर्क में गुजरकर जिससे हम आवश्यक प्रकार निकाल सकते हैं।

बीटीडब्ल्यू: # परिभाषित मैक्रोज़ या तो मदद नहीं करेगा। उपकरण जैसे?: दोनों के लिए एक ही प्रकार की आवश्यकता है? और: भाग।

तो यह सबसे अच्छा मैं क्या कर सकते हैं ...



बेशक

...

आप वापसी प्रकार की जरूरत नहीं है ...

यदि आप परिणाम को किसी अन्य फ़ंक्शन पर पास कर रहे हैं ...

आप ऐसा कुछ कर सकते हैं:

#include <iostream> 
using namespace std; 

struct FooA { 
    void operator()() {} 
}; 
struct FooB { 
    bool operator()() { return false; } 
}; 
struct FooC { 
    int operator()() { return 17; } 
}; 
struct FooD { 
    double operator()() { return 3.14159; } 
}; 
FooA fooA; 
FooB fooB; 
FooC fooC; 
FooD fooD; 

void barA() {} 
bool barB() { return false; } 
int barC() { return 17; } 
double barD() { return 3.14159; } 


#define SHOW(X) cout << # X " = " << (X) << endl; 

namespace N 
{ 
    template <typename T, typename R> 
    R run(T & t, R (T::*f)()) { return (t .* f)(); } 

    template <typename T> 
    bool run(T & t, void (T::*f)()) { (t .* f)(); return true; } 


    template <typename T> 
    void R(T & t) 
    { 
    SHOW(N::run(t, &T::operator())); 
    } 

    template <typename T> 
    void R(T (*f)()) 
    { 
    SHOW((*f)()); 
    } 

    void R(void (*f)()) 
    { 
    (*f)(); 
    SHOW(true); 
    } 
}; 


int main() 
{ 
    N::R(barA); 
    N::R(barB); 
    N::R(barC); 
    N::R(barD); 
    N::R(fooA); 
    N::R(fooB); 
    N::R(fooC); 
    N::R(fooD); 
} 
+0

इसका परीक्षण किया और यह जीसीसी 4.2.1 पर काम करता है। –

+0

"प्रिंट" सिर्फ यह तय करने के लिए है कि क्या हो रहा है ... मैं जो कर रहा हूं वह किसी और के एसिंच कॉलबैक तंत्र को पास करने के लिए तरीकों और कार्यों को लपेट रहा है। मेरी अधिकांश विधियां और फ़ंक्शंस शून्य हो जाती हैं - कभी-कभी मुझे तीसरे पक्ष के एसिंक कॉलबैक में बुलियन लौटने में सक्षम होना चाहिए। –

+0

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

1

शायद आप इस तथ्य का उपयोग कर सकते हैं कि & शून्य के रूप में समझ में नहीं आता है लेकिन शून्य * बनाता है।

-1

शून्य वापसी प्रकार के लिए विशेषज्ञ का प्रयास करें:

template<class F> 
class traits; 

template<class F, class T> 
class traits<T (F)()>; 

template<class F> 
class traits<void (F)()>; 

मुझे लगता है कि ...

0
सी के साथ

++ 0x आप decltype उपयोग करके आसानी से ऐसा कर सकता है।

+0

काम कैसे रद्द कर देगा? – paulm

0

यदि आप Boost का उपयोग कर सकते हैं, तो निम्न कोड संभवतः सेवा करेगा। मुझे लगता है कि आपके प्रश्न में सभी फ़ंक्शंस/फ़ैक्टर नुकीले हैं। हालांकि, इसका उपयोग करने के लिए, result_type को सभी फ़ंक्शंस (फ़ंक्शन क्लास) में परिभाषित किया जाना है।

#include <boost/utility/result_of.hpp> 
#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits.hpp> 
using namespace boost; // Sorry, for brevity 

template< class F > 
// typename result_of< F() >::type 
typename disable_if< 
    is_void< typename result_of< F() >::type > 
, typename result_of< F() >::type 
>::type 
f(F const& x) 
{ 
    return x(); 
} 

template< class F > 
typename enable_if< 
    is_void< typename result_of< F() >::type >, bool 
>::type 
f(F const& x) 
{ 
    x(); 
    return true; 
} 

template< class T > 
T f(T x()) 
{ 
    return x(); 
} 

bool f(void x()) 
{ 
    x(); 
    return true; 
} 

static void void_f() {} 
static int int_f() { return 1; } 

struct V { 
    typedef void result_type; 
    result_type operator()() const {} 
}; 

struct A { 
    typedef int result_type; 
    result_type operator()() const { return 1; } 
}; 

int main() 
{ 
    A a; 
    V v; 
    f(void_f); 
    f(int_f); 
    f(a); 
    f(v); 
} 

आशा इस मदद करता है

6

संकलन समय पर शून्य वापसी मान का पता लगाने के लिए, मानक चाल operator, ओवरलोड है। अल्पविराम ऑपरेटर के साथ अच्छी बात यह है कि यह एक शून्य पैरामीटर ले सकता है, और इस मामले में यह operator, में निर्मित के लिए डिफ़ॉल्ट है। कोड में:

template <typename> tag {}; 

template <typename T> 
tag<T> operator,(T, tag<void>); 

अब, expr, tag<void>() टाइप tag<typeof(expr)> भले ही expr शून्य टाइप है है। इसके बाद आप इसे सामान्य चाल के साथ पकड़ सकते हैं:

char (&test(tag<void>))[1]; 
template <typename T> char (&test(tag<T>))[2]; 

template <typename F> 
struct nullary_functor_traits 
{ 
    static const bool returns_void = sizeof(test((factory()(), tag<void>()))) == 1; 
private: 
    static F factory();  
}; 
संबंधित मुद्दे