2015-04-29 5 views
10

मेरे पास एक कक्षा है जो टेम्पलेट प्रकार पैरामीटर (टीटीआरआईटीआईटी) लेती है। मैं एक टेम्पलेट टाइपसदस्यउपनाम टीटीआरआईटीआईटी से मित्र बनाना चाहता हूं, लेकिन मैं वाक्यविन्यास नहीं समझ सकता। (क्या यह भी संभव है?)। (friend लाइन पर)सी ++: टेम्पलेट पैरामीटर के टेम्पलेट प्रकार के सदस्य को फेंकने के लिए सही वाक्यविन्यास?

template <bool bBOOL> 
struct SFoo {}; 

struct STrait 
    { 
     template <bool bBOOL> 
     using TFoo = SFoo<bBOOL>; 
    }; 

template <typename tTRAIT> 
struct SBar 
    { 
     template <bool bBOOL> 
     friend typename tTRAIT::template TFoo<bBOOL>; 
    }; 

SBar<STrait> bar; 

बजना की त्रुटि है:

error: friend type templates must use an elaborated type 

मैं सभी संभव संयोजनों मैं के बारे में सोच सकते हैं थकाऊ की कोशिश की है:

friend tTRAIT::TFoo; 
friend tTRAIT::template TFoo; 
friend typename tTRAIT::TFoo; 
friend typename tTRAIT::template TFoo; 
template <bool bBOOL> friend tTRAIT::TFoo; 
template <bool bBOOL> friend tTRAIT::TFoo<bBOOL>; 
template <bool bBOOL> friend tTRAIT::template TFoo; 
template <bool bBOOL> friend tTRAIT::template TFoo<bBOOL>; 
template <bool bBOOL> friend typename tTRAIT::TFoo; 
template <bool bBOOL> friend typename tTRAIT::TFoo<bBOOL>; 
template <bool bBOOL> friend typename tTRAIT::template TFoo; 
template <bool bBOOL> friend typename tTRAIT::template TFoo<bBOOL>; 

मैं भी using उपयोग करने की कोशिश की है, लेकिन यह मदद करने के लिए प्रतीत नहीं होता है।

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

friend typename tTRAIT::template TFoo<false>; 
friend typename tTRAIT::template TFoo<true >; 

लेकिन यह भाग्यशाली है।

क्या कोई यह जानता है कि यह कैसे करें, या यदि यह किया जा सकता है?

उत्तर

4

मुझे नहीं लगता कि यह संभव है। मानक प्रारूप N4296 से:

§ 14.5.4/1 [temp.friend]

कक्षा या वर्ग टेम्पलेट एक दोस्त एक समारोह टेम्पलेट या वर्ग टेम्पलेट, एक की एक विशेषज्ञता हो सकता है फ़ंक्शन टेम्पलेट या क्लास टेम्पलेट, या एक गैर-टेम्पलेट फ़ंक्शन या क्लास।

इसमें उपनाम टेम्पलेट्स शामिल नहीं हैं, इसलिए मानक आप जो करना चाहते हैं उसका समर्थन नहीं करता है।

§ 14.5.7/1 [temp.alias]

एक टेम्पलेट-घोषणा जिसमें घोषणा एक उपनाम-घोषणा है (: यह निम्नलिखित अंश (जोर मेरा) की वजह से शायद है खंड 7) पहचानकर्ता को को उपनाम टेम्पलेट घोषित करता है। एक उपनाम टेम्पलेट प्रकार के परिवार के लिए एक नाम है।

उपनाम वह टेम्पलेट नाम प्रकार की एक अलग परिवार है, तो भले ही कुछ वाक्य रचना है जो इस के लिए समझ में किए गए थे, आप टेम्पलेट जो एलियास की जा रही है उर्फ ​​टेम्पलेट के बजाय friending होगा।

उदाहरण के लिए, जीसीसी संकलन होगा यह (बजना नहीं होगा), लेकिन आप वास्तव में किसी भी उचित ढंग से दोस्ती उपयोग करने में सक्षम नहीं होगा:

template <bool B> 
using MyTFoo = typename tTRAIT::template TFoo<B>; 

template <bool> friend class MyTFoo; 

कैसे एक उपनाम टेम्पलेट है का एक और उदाहरण

template <template <typename...> class A, template <typename...> class B> 
struct is_same_template : std::false_type{}; 

template <template <typename...> class A> 
struct is_same_template<A,A> : std::true_type{}; 

template <typename T> using myvec = std::vector<T>; 

//this fails 
static_assert(is_same_template<myvec,std::vector>::value, "wat"); 

स्पष्ट इन्स्टेन्शियशन साथ आपका मार्गदर्शन friending, काम करेंगे क्योंकि उर्फ ​​टेम्पलेट aliased टेम्पलेट के रूप में वास्तव में एक ही प्रकार के लिए नीचे पतन होगा: aliased टेम्पलेट के रूप में ही नहीं। एक समान उदाहरण:

//this passes! 
static_assert(std::is_same<myvec<int>,std::vector<int>>::value, "wat"); 
+0

खैर कि, दिलचस्प और कष्टप्रद है, क्योंकि मैं सक्रिय रूप से बजना के साथ "मैन्युअल रूप से दोस्त और सत्य झूठी विशेषज्ञताओं" उपयोग कर रहा हूँ (3.7.0/C++ 1Z) और यह निश्चित रूप से वास्तविक (गैर-उपनाम) प्रकार को फेंक रहा है। शायद यह मेरे लिए अवैध रूप से अच्छा रहा है? – xaxazak

+0

संकलनकर्ता वर्गों और उनके आस-पास के कोड के विभिन्न संस्करणों को संकलित नहीं है (है ना?), एक वर्ग के लिए तो और यह उर्फ ​​है, या तो दोनों निजी सामान या न कर सकते हैं देख सकते हैं (उनके कार्यों के लिए केवल एक ही साझा संस्करण ऐसा के बाद से)। आप उन्हें अलग नहीं कर सकते हैं। – xaxazak

+0

मैनुअल friending के लिए, यह ठीक से काम करेंगे, क्योंकि उर्फ ​​टेम्पलेट के इन्स्टेन्शियशन और स्वयं टेम्पलेट को ठीक उसी प्रकार किया जाएगा। यह केवल टेम्पलेट्स हैं जो अलग हैं, तत्काल नहीं हैं। – TartanLlama

2

मैं std = C++ 11 मोड में क्लैंग 3.4.1 के साथ आगे बढ़ सकता हूं।

यह त्रुटि के बिना संकलित:

टेम्पलेट

struct SBar 
    { 
private: 
    int j; 
public: 
     template <bool bBOOL> 
     friend struct tTRAIT::TFoo; 
     void setJ(int j) { 
      this->j = j; 
     } 
}; 

लेकिन ... मैं इस चेतावनी मिलती है: चेतावनी: निर्भर नेस्टेड नाम निर्दिष्टकर्ता 'tTRAIT ::' दोस्त टेम्पलेट घोषणा के लिए समर्थित नहीं है; इस मित्र घोषणा को अनदेखा कर रहा है [-उत्पादित मित्र]: मित्र संरचना tTRAIT :: TFoo;

और मैं पुष्टि कर सकता है कि SFoo कक्षाएं दोस्त (private j के लिए कारण ...) नहीं हैं

एक ही रास्ता मैं यह सब संकलन और चलाने के लिए हो सकता है है:

struct SBar 
    { 
private: 
    int j; 
public: 
     template <bool bBOOL> 
     friend struct sFoo; 
     void setJ(int j) { 
      this->j = j; 
     } 
}; 

ठीक है, SFoo कक्षा दोस्त हैं, लेकिन यह कुछ हद तक ओपी आवश्यकता (टेम्पलेट पैरामीटर के टेम्पलेट प्रकार के सदस्य] को हरा देता है ...

मैं वर्तमान में एक हाल ही में जीसीसी के लिए कोई उपयोग कर सकते है लेकिन मुझे लगता है कि हम कैसे compilers मानक व्याख्या के किनारे पर यहाँ हैं। मैंने टार्टनलामा द्वारा संदर्भित अध्याय पढ़ा, लेकिन यह सुनिश्चित नहीं कर सका कि यह इरादा था या नहीं। हो सकता है कि मेरी पहली कोशिश जीसीसी द्वारा स्वीकार कर लिया जाएगा ...

+0

परीक्षण के लिए धन्यवाद। यदि आप चाहते हैं कि आप "स्ट्रैट" के साथ या उसके बिना "दोस्त tTRAIT :: TFoo " (और सत्य संस्करण) आज़मा सकते हैं। ऐसा लगता है कि सी ++ 1z पर मेरे लिए काम करना प्रतीत होता है। – xaxazak

+0

@xaxazak: यह नहीं करता है। लेकिन यह 'मित्र स्ट्रेट :: टीएफयू ;' स्वीकार करता है। ऐसा लगता है कि सी ++ 1z में आप 3.7 सी ++ 11 में अपने 3.4 से अधिक सहनशील हैं ... –

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