2012-06-12 27 views
6
#include <iostream> 
#include <tuple> 
int main(){ 

auto bt=std::make_tuple(std::tuple<>(),std::tuple<std::tuple<>>()); //Line 1 
auto bt2=std::make_tuple(std::tuple<>(),std::tuple<>());    //Line 2 
} 

लाइन 2 संकलन त्रुटि क्यों देता है जबकि लाइन 2 ठीक से संकलित करता है? (जीसीसी & क्लैंग दोनों में परीक्षण किया गया)खाली नेस्टेड टुपल्स त्रुटि

क्या कोई संभावित कामकाज है? जैसे आप libstdc में एक बग मिला

बजना

/usr/include/c++/4.6/tuple:150:50: error: ambiguous conversion from derived class 'std::_Tuple_impl<0, std::tuple<>, 
     std::tuple<std::tuple<> > >' to base class 'std::_Head_base<0, std::tuple<>, true>': 
    struct std::_Tuple_impl<0, class std::tuple<>, class std::tuple<class std::tuple<> > > -> _Tuple_impl<0UL + 1, class std::tuple<class std::tuple<> > > -> _Head_base<1UL, class std::tuple<class std::tuple<> >, std::is_empty<class tuple<class tuple<> > >::value> -> class std::tuple<class std::tuple<> > -> _Tuple_impl<0, class std::tuple<> > -> _Head_base<0UL, class std::tuple<>, std::is_empty<class tuple<> >::value> 
    struct std::_Tuple_impl<0, class std::tuple<>, class std::tuple<class std::tuple<> > > -> _Head_base<0UL, class std::tuple<>, std::is_empty<class tuple<> >::value> 
     _Head&   _M_head()  { return _Base::_M_head(); } 
               ^~~~~ 
/usr/include/c++/4.6/tuple:173:33: note: in instantiation of member function 'std::_Tuple_impl<0, std::tuple<>, 
     std::tuple<std::tuple<> > >::_M_head' requested here 
     _Base(std::forward<_Head>(__in._M_head())) { } 
            ^
/usr/include/c++/4.6/tuple:334:9: note: in instantiation of member function 'std::_Tuple_impl<0, std::tuple<>, 
     std::tuple<std::tuple<> > >::_Tuple_impl' requested here 
     : _Inherited(static_cast<_Inherited&&>(__in)) { } 
     ^
gcc_bug.cpp:5:10: note: in instantiation of member function 
     'std::tuple<std::tuple<>, std::tuple<std::tuple<> > >::tuple' requested here 
     auto bt=std::make_tuple(std::tuple<>(),std::tuple<std::tuple<>>()); 
       ^
1 error generated. 
+0

यह जीसीसी या बजना में एक बग हो सकता है (ध्यान दें कि, इस टपल <> प्रकार के लिए केवल का सहारा समाधान है, यह KennyTM द्वारा वर्णित वास्तविक समस्या है, यानी struct A{}; auto d = std::tuple<std::tuple<std::tuple<A, A>, A>, A>{}; अभी भी संकलन नहीं है समाधान नहीं करता है)? आपका कोड विजुअल स्टूडियो 2010 के साथ संकलित करता है। वैसे, आप दो बार बीटी घोषित कर रहे हैं, क्या इसका इरादा है? –

+1

इसके अलावा, क्या आप संकलन त्रुटि संदेश इंगित कर सकते हैं? –

+0

क्षमा करें, छोटी गाड़ी लाइन 1 टिप्पणी की गई थी। मैं नाम बदलना भूल गया, अब संपादित किया गया। – dunedain

उत्तर

12

के लिए त्रुटि संदेश दिखता ++! (यह कोड libC++ के साथ clang में काम करता है)। एक छोटा संस्करण परीक्षण का मामला:

#include <tuple> 

int main(){ 
    auto b = std::tuple<std::tuple<std::tuple<>>>{}; 
} 

समस्या कैसे std::tuple libstdc में कार्यान्वित किया जाता ++ के कारण है। ट्यूपल कार्यान्वयन एकाधिक विरासत के साथ "रिकर्सन" का उपयोग करता है। X और tuple<Y, Z> दोनों से विरासत के रूप में आप सोच सकते हैं। इसका मतलब है tuple<tuple<>>tuple<> और tuple<> दोनों से प्राप्त होगा और इससे एक अस्पष्ट आधार त्रुटि होगी। बेशक वास्तविक समस्या इस तरह नहीं है, क्योंकि tuple<tuple<>> कोई त्रुटि उत्पन्न नहीं करता है।

वास्तविक कार्यान्वयन कि त्रुटि के कारण इस तरह है:

template<size_t _Idx, typename _Head> 
struct _Head_base : public _Head 
{}; 

template<size_t _Idx, typename... _Elements> 
struct _Tuple_impl; 

template<size_t _Idx> 
struct _Tuple_impl<_Idx> {}; 

template<size_t _Idx, typename _Head, typename... _Tail> 
struct _Tuple_impl<_Idx, _Head, _Tail...> 
    : public _Tuple_impl<_Idx + 1, _Tail...>, 
     private _Head_base<_Idx, _Head> 
{ 
    typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited; 
    constexpr _Tuple_impl() = default; 
    constexpr _Tuple_impl(_Tuple_impl&& __in) : _Inherited(std::move(__in)) {} 
}; 

template<typename... _Elements> 
struct tuple : public _Tuple_impl<0, _Elements...> {}; 

जब हम tuple<tuple<tuple<>>> का दृष्टांत, हम इस वंशानुगत पदानुक्रम मिलती है:

inheritance diagram of <code>tuple<tuple<tuple<>>></code> in libstdc++

हम देखते हैं कि _Tuple_impl<1> दो में पहुंचा जा सकता है विभिन्न पथ यह अभी तक समस्या नहीं है, समस्या कन्स्ट्रक्टर में है, जो _Tuple_impl<1> के चाल-रूपांतरण कन्स्ट्रक्टर को आमंत्रित करती है। कौन सा _Tuple_impl<1> आप चाहते हैं? कंपाइलर नहीं जानता है, इसलिए यह हार छोड़ देता है।

(आपके मामले में यह _Head_base<0, tuple<>> की वजह से के रूप में आप tuple<tuple<>, tuple<tuple<>>> बजाय instantiating हैं, लेकिन सिद्धांत एक ही है।)


क्यों libC++ एक ही समस्या नहीं है?

  1. tuple<T...> libC++ उपयोग रचना के बजाय विरासत में __tuple_impl<...> का उल्लेख करने के: दो मुख्य कारण हैं।
  2. नतीजतन, __tuple_leaf<tuple<tuple<>>> में खाली आधार वर्ग अनुकूलन में लात नहीं करता है, अर्थात __tuple_leaf<tuple<tuple<>>> से tuple<tuple<>>
  3. लागू नहीं होंगे इसलिए, अस्पष्ट आधार वर्ग समस्या नहीं होगा।
  4. (और प्रत्येक आधार के रूप में @mitchnull ने उल्लेख किया, लेकिन यह एक मुख्य अंतर यह यहाँ नहीं है अद्वितीय है।)

inheritance diagram of <code>tuple<tuple<tuple<>>></code> in libc++

हम ऊपर देख सकते हैं, अगर tuple<...> रचना के बजाय विरासत का उपयोग करता है, ओपी का tuple<tuple<>, tuple<tuple<>>> अभी भी __tuple_leaf<0, tuple<>> से दो बार होगा, जो एक समस्या हो सकती है।

+0

मैं देखता हूं, libC++ एक nonrecursive tuple कार्यान्वयन का उपयोग करता है? – dunedain

+0

@ ड्यूनडेन: रिकर्सिव। अद्यतन देखें। – kennytm

+0

स्पष्ट और विस्तृत उत्तर के लिए धन्यवाद। – dunedain

0

वैसे, उन जीसीसी उपयोग करने के लिए जो के लिए, मैं आपको एक त्वरित और गंदा ठीक देना (4.8.0 के लिए, पहले से ही एक बग रिपोर्ट प्रस्तुत) करते हैं:

समाधान एक छोटा सा संशोधन है टपल कार्यान्वयन में __empty_not_final की, टपल < के लिए खाली आधार अनुकूलन को रोकने के लिए> प्रकार:

template<typename _Tp> 
    using __empty_not_final 
     = typename conditional<__is_final(_Tp)||is_same<_Tp,tuple<>>::value, 
false_type, is_empty<_Tp>>::type; 

template<typename _Tp> 
    using __empty_not_final 
     = typename conditional<__is_final(_Tp), false_type, is_empty<_Tp>>::type; 
के बजाय 210

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