2010-04-27 22 views
5

इस question का जवाब पढ़ने के बाद, मुझे पता चला कि SFINAE दो कि क्या वर्ग एक निश्चित सदस्य समारोह के आधार पर काम करता है के बीच चयन करने के लिए इस्तेमाल किया जा सकता। यह निम्नलिखित के बराबर है, बस यह है कि अगर बयान में प्रत्येक शाखा एक ओवरलोड समारोह में विभाजित है:एकाधिक SFINAE नियम

template<typename T> 
void Func(T& arg) 
{ 
    if(HAS_MEMBER_FUNCTION_X(T)) 
     arg.X(); 
    else 
     //Do something else because T doesn't have X() 
} 

हो जाता है

template<typename T> 
void Func(T &arg, int_to_type<true>); //T has X() 

template<typename T> 
void Func(T &arg, int_to_type<false>); //T does not have X() 

अगर यह SFINAE विस्तार करने के लिए कई करने के लिए संभव हो गया था मैं सोच रहा था नियम। कुछ ऐसा है जो इस बात का बराबर होगा:

template<typename T> 
void Func(T& arg) 
{ 
    if(HAS_MEMBER_FUNCTION_X(T))    //See if T has a member function X 
     arg.X(); 
    else if(POINTER_DERIVED_FROM_CLASS_A(T)) //See if T is a pointer to a class derived from class A 
     arg->A_Function();    
    else if(DERIVED_FROM_CLASS_B(T))   //See if T derives from class B 
     arg.B_Function(); 
    else if(IS_TEMPLATE_CLASS_C(T))    //See if T is class C<U> where U could be anything 
     arg.C_Function(); 
    else if(IS_POD(T))       //See if T is a POD type 
     //Do something with a POD type 
    else 
     //Do something else because none of the above rules apply 
} 

यह संभव तरह कुछ है?

धन्यवाद।

उत्तर

6

यह निश्चित रूप से संभव है; आपको बस यह सुनिश्चित करने के लिए सावधान रहना होगा कि सभी शाखा पारस्परिक रूप से अनन्य हैं, अन्यथा आप एक अस्पष्टता के साथ समाप्त हो जाएंगे।

Boost Type Traits और Boost Enable If पर एक नज़र डालें, जो इसका समर्थन करने के लिए दो सबसे अच्छे उपकरण हैं। Boost ICE (जो इंटीग्रल लगातार अभिव्यक्ति के लिए खड़ा है) आप और अधिक जटिल प्रकार मिलान करने के लिए (और सुनिश्चित करें कि आपके भार के परस्पर अनन्य हैं मदद करने के लिए कई प्रकार के लक्षण गठबंधन करने के लिए इस्तेमाल किया जा सकता।

यह कुछ हद तक जटिल और जटिल हो सकता है तो यहाँ एक अपेक्षाकृत सरल उदाहरण मान लीजिए कि आप एक वर्ग पदानुक्रम है:।

struct Base { }; 
struct Derived : Base { }; 

और आप Base के लिए एक समारोह foo में से एक अधिभार, और Base से प्राप्त किसी भी वर्ग के लिए एक और अधिभार कॉल करना चाहते हैं एक पहला प्रयास की तरह लग रहे हो सकता है। :

#include <boost/type_traits.hpp> 
#include <boost/utility/enable_if.hpp> 

using namespace boost; 
using namespace boost::type_traits; 

template <typename T> 
typename enable_if<is_same<Base, T>, void>::type 
foo(const T&) { } 

template <typename T> 
typename enable_if<is_base_of<Base, T>, void>::type 
foo(const T&) { } 

हालांकि, is_base_of रिटर्न सच अगर T, आधार वर्ग है, इसलिए यदि आप foo(Base()) कॉल करने का प्रयास है, वहाँ क्योंकि दोनों समारोह टेम्पलेट्स मैच एक अस्पष्टता है। हम प्रकार के लक्षण के संयोजन का उपयोग और बूस्ट बर्फ सहायकों का उपयोग करके इस को हल कर सकते हैं:

template <typename T> 
typename enable_if<is_same<Base, T>, void>::type 
foo(const T&) { } 

template <typename T> 
typename enable_if< 
    ice_and< 
     is_base_of<Base, T>::value, 
     ice_not<is_same<Base, T>::value>::value 
    >, void>::type 
foo(const T&) { } 

ये भार के परस्पर अनन्य हैं, और वे यह सुनिश्चित कोई अस्पष्टता नहीं है।

आपके कुछ उदाहरण समर्थित नहीं हैं (अर्थात्, HAS_MEMBER_FUNCTION_X; मुझे यकीन नहीं है कि IS_TEMPLATE_CLASS_C - आप इसके साथ क्या करना चाहते हैं, इस पर निर्भर करते हुए आप कुछ काम करने में सक्षम हो सकते हैं), लेकिन सामान्य रूप से यह संभव है ।

+0

धन्यवाद (जाहिर है, जब बुला आप के रूप में विकल्प परस्पर अनन्य नहीं हैं देखभाल करने के लिए है)। मैं IS_TEMPLATE_CLASS_C उदाहरण को छोड़कर enable_if का उपयोग कर सबकुछ काम करने में कामयाब रहा हूं। क्या is_base_of के समान कुछ लिखने का कोई तरीका है जो काम करेगा? अर्थात is_template_of < C, T > :: मान हमेशा सही हो सकता है अगर टी सी , सी , आदि था, और बाकी सब – Fred

+0

@Fred के लिए झूठी: समस्या यह है कि 'सी ' और 'सी ' असंबंधित प्रकार के होते हैं है। मेरा पहला विचार कुछ टाइपिफ़ या अभिन्न प्रकार के सदस्य को 'IsInstantiatedTemplateC' नामक वर्ग टेम्पलेट' सी 'में जोड़ना होगा और इसके अस्तित्व के लिए परीक्षण करना होगा। या आप क्लास टेम्पलेट 'सी' को रिक्त वर्ग 'बेससी' से सार्वजनिक रूप से प्राप्त कर सकते हैं और उस प्रकार से विरासत के लिए परीक्षण कर सकते हैं। यह जानना एक अजीब चीज है कि एक प्रकार का कुछ टेम्पलेट का तात्कालिकता है या नहीं; आम तौर पर जब तक कि कुछ ज्ञात इंटरफेस लागू करता है तब तक आप परवाह नहीं करते हैं। –

1

जिस तरह से आपने इसे कार्यान्वित किया है, नहीं। अगर तर्क में कोई कार्य नहीं है तो संकलन विफल हो जाएगा। (मुझे लगता है कि आप यह जानते हैं, बस सुनिश्चित कर रहे हैं)।

हालांकि, यह इतना टेम्पलेट विशेषज्ञता (बढ़ावा एमपीएल के जादू में छिपा) का उपयोग करने के लिए संभव है।

यदि आप कुछ समय मेटा-कार्यों के साथ इस का उपयोग करते हुए बढ़ावा एमपीएल वेक्टर कर सकता है: वास्तव में आवश्यकताओं के आधार पर http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual.html

typedefs typename mpl::vector<f0,f1,...>::type handlers; // different handlers 
// convert logic to int N to map condition to handler 
// can use ternary or bit shift trick 
// more general approach could be to use vector of mpl::bool_ and mpl::find 

typedef typename mpl::vector_c<bool, (first_condition), 
            (second_condition),...>::type condition; 

typedef typename mpl::find<condition, mpl:: bool_<true> >::type iterator; 
typedef typename mpl::at<handlers, iterator::pos::value>::type handler; 
handler::apply(...); // call handler with some arguments 

की जाँच, आप अलग दृष्टिकोण की कोशिश कर सकते हैं। से ऊपर कुछ किया है है कुछ घंटे पहले

+1

अपने दूसरे उदाहरण का पूरा बिंदु वास्तव में यह दिखाने के लिए है कि हम क्या चाहते हैं। यह संकलित नहीं करता है, जैसा कि पहले नहीं था। लेकिन वहां उन्होंने एक संकलन विकल्प प्रदान किया। – MSalters

1

सवाल जब आपको लगता है कि

if (a) { X(); } 
else if (b) { Y(); } 

का मतलब है ठीक उसी

रूप
if (a) { X(); } 
if (!a && b) { Y(); } 

हालांकि, अगर आप भी अपने true/false विरोधाभास का विस्तार कर सकता है आसान है।

enum FuncVariants { HasMember, PointerDerivedFromA, DerivedFromB, InstanceOfC, isPod } 
template<typename T> 
void Func(T &arg, int_to_type<HasMember>); 

template<typename T> 
void Func(T &arg, int_to_type<DerivedFromA>); 

template<typename T> 
void Func(T &arg, int_to_type<DerivedFromB>); 

template<typename T> 
void Func(T &arg, int_to_type<InstanceOfC>); 

सुझाव जेम्स के लिए

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