7

मैं एक प्रकार की संरचना परिभाषा में कुल प्रकारों के लिए सी ++ में एकाधिक वर्चुअल विरासत वाले विविध चर टेम्पलेट का उपयोग कर रहा हूं।सी ++ 11 वैरिएडिक टेम्पलेट तर्कों से डुप्लिकेट प्रविष्टियों को हटाएं

यहाँ संरचनाओं का एक नमूना सेट है:

struct meas { int i; }; 
struct meas2 : public virtual meas { int j; }; 
struct meas3 : public virtual meas { int k; }; 

मैं तो इन का उपयोग कर कई आभासी विरासत कुल:

template <typename... Args> 
struct zipper : public virtual Args... {}; 

मैं तो कर सकते हैं:

typedef zipper<meas, meas2> meas_type; 
meas* m = new meas_type; 

ये तो कर सकते हैं कैस्केड:

gdb के अनुसार

$46 = (zipper<meas3, zipper<meas, meas2> >) { 
    <meas3> = { 
    <meas> = { 
     i = 0 
    }, 
    members of meas3: 
    _vptr.meas3 = 0x400ec8, 
    k = 0 
    }, 
    <zipper<meas, meas2>> = { 
    <meas2> = { 
     members of meas2: 
     _vptr.meas2 = 0x400ee0, 
     j = 6299120 
    }, 
    members of zipper<meas, meas2>: 
    _vptr.zipper = 0x400eb0 
    }, <No data fields>} 

:

जिसके परिणामस्वरूप वस्तु है, तथापि, बल्कि बोझल है।

वहाँ भी एक माध्यमिक समस्या है जब एक ही आधार प्रकार ज़िप करने का प्रयास कर रहा है:

typedef zipper<meas, meas> meas_type2; 

ऊपर संकलक त्रुटि पैदा करता है जी के तहत ++ 4.6.3 "डुप्लीकेट आधार वर्ग 'meas' अमान्य है"।

प्रश्न इस प्रकार दोहरा है:

  1. वहाँ zipper<meas3, meas2> में zipper<meas3, zipper<meas, meas2>> को बदलने के लिए कोई तरीका है?
  2. टाइप सूची में डुप्लिकेट प्रविष्टियों को हटाने के लिए # 1 को पूरा करते समय कोई तरीका है?

धन्यवाद!

+1

आप समतल के साथ-साथ डुप्लिकेट निकालना चाहते हैं। – Nawaz

+0

@ नवाज़ बिल्कुल! –

+0

आपके प्रश्न 1 के लिए, क्या आप 'जिपर <मापन 3, माप, माप 2>' में बदलना चाहते थे? ऐसा लगता है कि आपने 'माप' भाग गिरा दिया है। –

उत्तर

7

इस समस्या को हल करने के लिए मेरी रणनीति संकेत के कुछ स्तरों का उपयोग करना है।

  • ज़िपर < args ...> इनहेरिट द्वारा एक समारोह process_zipper_arguments को अपने तर्कों का इलाज डिस्पैच:

उदाहरण:

template < typename... Args > 
struct zipper : zipper < typename process_zipper_arguments <Args...>::type > {}; 
  • एक template < typename... Args > struct typelist {} का उपयोग का ट्रैक रखने के ऑब्जेक्ट प्रकार जिनसे आप वारिस करना चाहते हैं।
  • विशेषज्ञ struct zipper < typelist <Args...> >: public virtual Args... वास्तविक विरासत

आदेश में नकली माता पिता प्रकार से छुटकारा पाने के लिए क्या करना, दो सहायक कार्यों process_zipper_arguments में किया जाता है:

  • is_in < CandidateType, typelist<Args...> >::type या तो true_type या false_type है और परिभाषित किया जा सकता रिकर्सिव
  • add_unique < CandidateType, typelist<Args...> >::typetypelist <...> है जिसमें या तो उम्मीदवार टाइप इसमें शामिल है या नहीं। यह निर्धारित करने के लिए is_in पर कॉल करता है।

यहां पूरा कोड है जो कम से कम g ++ (GCC) 4.6.3 के साथ --std = C++ 0x के साथ संकलित करता है। इस पर आलोचना का स्वागत है।

// Forward declarations 
template < typename... Args > 
struct zipper; 

// Two types meaning true and false 
struct true_type {}; 
struct false_type {}; 

// The only purpose of this struct is to be associated with Types... 
template < typename... Types > 
struct typelist {}; 


// =================================================== 
// is_in < type, typelist<...> >::type 
//  is true_type if type is in typelist 
//  is false_type if type is not in typelist 

// Assume TElement is not in the list unless proven otherwise 
template < typename TElement, typename TList > 
struct is_in { 
    typedef false_type type; 
}; 

// If it matches the first type, it is definitely in the list 
template < typename TElement, typename... TTail > 
struct is_in < TElement, typelist < TElement, TTail... > > 
{ 
    typedef true_type type; 
}; 

// If it is not the first element, check the remaining list 
template < typename TElement, typename THead, typename... TTail > 
struct is_in < TElement, typelist < THead, TTail... > > 
{ 
    typedef typename is_in < TElement, typelist <TTail...> >::type type; 
}; 

// =================================================== 
// add_unique < TNew, typelist<...> >::type 
//  is typelist < TNew, ... > if TNew is not already in the list 
//  is typelist <...> otherwise 

// Append a type to a type_list unless it already exists 
template < typename TNew, typename TList, 
    typename Tis_duplicate = typename is_in < TNew, TList >::type 
    > 
struct add_unique; 

// If TNew is in the list, return the list unmodified 
template < typename TNew, typename... TList > 
struct add_unique < TNew, typelist <TList...>, true_type > 
{ 
    typedef typelist <TList...> type; 
}; 

// If TNew is not in the list, append it 
template < typename TNew, typename... TList > 
struct add_unique < TNew, typelist <TList...>, false_type > 
{ 
    typedef typelist < TNew, TList... > type; 
}; 

// =================================================== 
// process_zipper_arguments <Args...>::type 
//  returns a typelist of types to be inherited from. 
// 
// It performs the following actions: 
// a) Unpack zipper<...> and typelist <...> arguments 
// b) Ignore values that are already in the list 

template < typename... Args > 
struct process_zipper_arguments; 

// Unpack a zipper in the first argument 
template < typename... ZipperArgs, typename... Args > 
struct process_zipper_arguments < zipper <ZipperArgs...>, Args... > 
{ 
    typedef typename process_zipper_arguments < ZipperArgs..., Args... >::type type; 
}; 

// Unpack a typelist in the first argument 
template < typename... TypeListArgs, typename... Args > 
struct process_zipper_arguments < typelist <TypeListArgs...>, Args... > 
{ 
    typedef typename process_zipper_arguments < TypeListArgs..., Args... >::type type; 
}; 

// End the recursion if the list is empty 
template < > 
struct process_zipper_arguments < > 
{ 
    typedef typelist < > type; 
}; 

// Construct the list of unique types by appending them one by one 
template < typename THead, typename... TTail > 
struct process_zipper_arguments < THead, TTail... > 
{ 
    typedef typename 
    add_unique < THead, 
     typename process_zipper_arguments <TTail...>::type 
    >::type type; 
}; 


// =================================================== 
// The zipper class that you might want 


// If the list of types is not yet known, process it. 
// The inheritance is ugly, but there is a workaround 
template < typename... Args > 
struct zipper : zipper < typename process_zipper_arguments <Args...>::type > 
{ 
    // // Instead of inheriting, you can use zipper as a factory. 
    // // So this: 
    // typedef zipper < meas2, zipper < meas1, meas > > mymeas; 
    // // Turns to: 
    // typedef typename zipper < meas2, zipper < meas1, meas > >::type mymeas; 
    typedef zipper < typename process_zipper_arguments <Args...>::type > type; 
}; 

// If the list of types is known, inherit from each type 
template < typename... Args > 
struct zipper < typelist <Args...> > 
: public virtual Args... 
{}; 

// =================================================== 
// Short usage demo, replace with your own code 

struct meas { 
    int i; 
}; 

struct meas2 { 
    int j; 
}; 

struct meas3 { 
    int k; 
}; 


typedef zipper < meas, meas, meas3 > meas_type; 
typedef zipper < meas2, meas_type, meas2 > meas_type2; 

typedef typename zipper <meas_type2>::type nicer_meas_type2; 


int main (int, char**) 
{ 
    meas * m = new meas_type2; 
    meas_type2 n; 
    nicer_meas_type2 o; 

    return 0; 
} 

डिबगिंग यह (return 0; लाइन पर ब्रेकप्वाइंट) परिणाम निम्न देता है:

(gdb) print *m 
$1 = {i = 0} 
(gdb) print n 
$2 = {<zipper<typelist<meas, meas3, meas2> >> = {<meas> = {i = 4196320}, <meas3> = {k = 0}, <meas2> = {j = 0}, 
    _vptr.zipper = 0x400928}, <No data fields>} 
(gdb) print o 
$3 = {<meas> = {i = 4195719}, <meas3> = {k = 0}, <meas2> = {j = 1}, _vptr.zipper = 0x4009a8 <VTT for zipper<typelist<meas, meas3, meas2> >>} 
+0

यह महाकाव्य है और वास्तव में मैं क्या देख रहा था! आपका टेम्पलेट फू काफी मजबूत है :) –

+0

धन्यवाद, लेकिन ईमानदार होने के लिए, मुझे एक हफ्ते पहले एक जैसी ही समस्या का सामना करना पड़ रहा था, जिसने मुझे कुछ समय लगाया, इसलिए यह अभी भी मेरे सिर में ताजा था। – mars

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