2010-08-08 12 views
5

मैं SFINAE का उपयोग उस वर्ग को अलग करने के लिए कर रहा हूं जिसमें 'नाम' नामक सदस्य है। मैंने चीजों को मानक पैटर्न के रूप में स्थापित किया है लेकिन यह काम नहीं कर रहा है - चुपचाप 'विफल' प्रतिस्थापन को अनदेखा करने के बजाय, संकलक एक त्रुटि उत्पन्न करता है।SFINAE: कुछ विफलताओं दूसरों की तुलना में अधिक बराबर है?

मुझे यकीन है कि मैंने कुछ टेम्पलेट प्रतिस्थापन नियम के खिलाफ भाग लिया है, अगर कोई व्यक्ति समझा सकता है तो मैं आभारी रहूंगा।

यह एक अलग उदाहरण है। मैं जीसीसी उपयोग कर रहा हूँ:

template <typename U> string test(char(*)[sizeof(U::name)] = 0) { return "has name!"; } 
template <typename U> string test(...) { return "no name"; } 

struct HasName { string name; } 
struct NoName {} 

cout << "HasName: " << test<HasName>(0) << endl; //fine 
cout << "NoName: " << test<NoName>(0) << endl; //compiler errors: 

//error: size of array has non-integral type `<type error>' 
//error: `name' is not a member of `NoName' 
+0

आप किस कंपाइलर का उपयोग कर रहे हैं? g ++ 4.4.3 इस कोड को स्वीकार करता है और '-Wall -Wextra -pedantic' के साथ भी कोई निदान नहीं करता है। –

+3

@ टाइलर: क्या यह 'संरचना' परिभाषाओं के बाद लापता अर्ध-कॉलन के लिए निदान भी नहीं करता है? ;-) –

+0

ओह :-); मुझे यकीन है कि यह करता है (लापरवाही टाइपिंग को क्षमा करें) –

उत्तर

1

निम्नलिखित वैध प्रतीत होता है (हालांकि माइकल कहते हैं, यह जरूरी परिणाम आप अन्य compilers पर चाहते हैं नहीं देता है):

#include <string> 
#include <iostream> 
using namespace std; 

template <typename U> string test(char(*)[sizeof(U::name)] = 0) { return "has name!"; } 
template <typename U> string test(...) { return "no name"; } 

struct HasName { static string name; }; 
struct NoName { }; 

int main() { 
    cout << "HasName: " << test<HasName>(0) << endl; 
    cout << "NoName: " << test<NoName>(0) << endl; 
} 

आउटपुट:

HasName: has name! 
NoName: no name 

जीसीसी (जीसीसी) 4.3.4 20,090,804 (रिलीज) 1

Comeau भी कोड को स्वीकार करता है ।

+0

कुछ अतिरिक्त डेटा पॉइंट्स: एमएसवीसी 9/10 कोड को स्वीकार करता है (यहां तक ​​कि 'नाम' सदस्य पर 'स्थिर' के बिना), लेकिन अपेक्षित आउटपुट का उत्पादन नहीं करता है। मिनजीडब्ल्यू (जीसीसी 3.4.5) सदस्य को 'स्थिर' के साथ या उसके बिना संकलित नहीं करता है। –

+0

@ माइकल: तो शायद मुझे कहना चाहिए "ठीक दिखाई देता है"। मैं आम तौर पर "इसे वैध सी ++" के समानार्थी के रूप में "क्वॉउ स्वीकार करता है" लेता हूं, लेकिन मुझे लगता है कि यह केवल एक बहुत अच्छा अनुमान है :-) –

+0

ओह, और जब कमौ कोड को स्वीकार करता है, तो यह उसी आउटपुट का उत्पादन करता है जो एमएसवीसी (जो है , यह 'कॉल <>() 'दोनों कॉल के लिए" कोई नाम नहीं "कहता है। –

0

यहाँ इस पर एक प्रयास है:

// Tested on Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 
template<typename T> 
class TypeHasName 
{ 
private: 
    typedef char (&YesType)[2]; 
    typedef char (&NoType)[1]; 

    struct Base { int name; }; 
    struct Derived : T, Base { Derived(); }; 

    template<typename U, U> struct Dummy; 

    template<typename U> 
    static YesType Test(...); 

    template<typename U> 
    static NoType Test(Dummy<int Base::*, &U::name>*); 

public: 
    enum { Value = (sizeof(Test<Derived>(0)) == sizeof(YesType)) }; 
}; 

#include <string> 
#include <iostream> 

struct HasName { std::string name; }; 
struct NoName {}; 

int main() 
{ 
    std::cout << "HasName: " << TypeHasName<HasName>::Value << std::endl; 
    std::cout << "NoName: " << TypeHasName<NoName>::Value << std::endl; 
    return 0; 
} 

विचार यह है कि अगर Tname नामक एक चर है, तो Derived दो name चर (T से एक और Base से एक) होगा। यदि Tname चर घोषित नहीं करता है, तो Derived में केवल Base से एक होगा।

हैं Derived दो name चर, तो दूसरी Test() अधिभार में अभिव्यक्ति &U::name अस्पष्ट हो जाएगा और SFINAE अधिभार सेट से कि समारोह को निकाल देना चाहिए है।

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