2012-04-25 12 views
5

मैं एक वर्ग की तरह की सोच रहा था:मैं सशर्त रूप से डिफ़ॉल्ट-निर्माता को कैसे परिभाषित कर सकता हूं?

template < typename ...Whatever > 
class MyClass 
{ 
public: 
    static constexpr bool has_default_ctr = Something; 

    // I want this only if "has_default_ctr" is "true". 
    MyClass(); 

    //... 
}; 

मुझे नहीं लगता कि मैं एक निर्माता टेम्पलेट है और इस के लिए std::enable_if उपयोग कर सकते हैं (क्योंकि वहाँ कोई तर्क)। क्या मै गलत हु? यदि नहीं, तो ऐसा करने का कोई और तरीका है?

+0

बस एक त्वरित सोचा - यदि आप एक डिफ़ॉल्ट मान के साथ एक बहस के साथ enable_if' और एक निर्माता का प्रयास किया '? –

+2

क्या आप विस्तारित कर सकते हैं कि आप ऐसा क्यों करना चाहते हैं? –

+0

ठीक है, मैंने ईमानदारी से सोचा कि यह संभव नहीं था, मैं सही जवाब देता हूं और अपना जवाब हटा देता हूं। हालांकि यह एक बड़ा विरोधी पैटर्न नहीं है? – verhage

उत्तर

-1

आप और विभिन्न तर्क

MyClass(){ 

} 
MyClass(int num){ 

} 
MyClass(String s){ 
} 

साथ विभिन्न निर्माताओं का उपयोग कर सकते आप कर सकते हैं सरल लिखने और स्थिर समारोह है कि वर्ग लौट सकते हैं और अंदर की स्थिति लिखते हैं:

static chooseContructor(/*parameters*/){ 
if(/*something*/){ 
    return new MyCLass(); 
} 
else if(/*something else*/){ 
    return new MyClass(int num); 
} 
else if{ 
    return new MyClass(String s); 
} 
} 

और इसी तरह .. ऐसा कुछ आपको अर्द्ध स्वचालित कन्स्ट्रक्टर चुनने वाला

+0

यदि यह 'MyClass' में ऐसे सदस्य हैं जो डिफ़ॉल्ट रूप से रचनात्मक नहीं हैं तो यह विफल हो जाता है। –

10

C++ 11 (विश्वसनीय रूप से)का उपयोग करने की अनुमति देता हैशैली टेम्पलेट बहस में SFINAE:

template< 
    // This is needed to make the condition dependent 
    bool B = has_default_ctr 
    , typename std::enable_if<B, int>::type = 0 
> 
MyClass(); 

// When outside of class scope: 
// have to repeat the condition for out-of-line definition 
template<bool B, typename std::enable_if<B, int>::type = 0> 
MyClass::MyClass() 
/* define here */ 

में सी ++ 03 यदि आप एक डिफॉल्ट पैरामीटर के साथ एक एकल निर्माता इस्तेमाल किया जा सकता था - डिफ़ॉल्ट पैरामीटर मतलब यह है कि निर्माता अभी भी एक डिफ़ॉल्ट निर्माता के रूप में गिना जाता है।

+0

मेरे भगवान आदमी यह चाल मेरे लिए बहुत उपयोगी है। मुझे std :: enable_if के बारे में पता था, लेकिन इस तरह से इसका उपयोग करने के बावजूद –

+0

मुझे लगता है कि यह संकलन-समय त्रुटि में परिणाम देता है। जब तक मुझे कुछ याद नहीं आ रहा है, तब तक टाइप नहीं किया गया है std :: enable_if :: टाइप = 0' 'v = true' जब' v = true' को हल करें? 'वर्ग सी = टाइपनाम std :: enable_if :: टाइप' काम करेगा। –

+0

@ शून्य-सूचक प्रतिस्थापन 'int = 0' पैदा करता है। –

0

किसी शर्त के आधार पर कक्षा के लिए अलग-अलग परिभाषाएं प्राप्त करने के लिए, टेम्पलेट तर्क में निर्भरता गणना रखें।

// primary template, no default constructor unless Something is true 
template< typename T, bool has_default_ctr = Something > class MyClass { 
    // as you had it, with no default constructor 
}; 

// you want MyClass<T,true> to be just like MyClass<T,false> 
// but with a default constructor: 
template< typename T > class MyClass<T,true> : public MyClass<T,false> { 

    MyClass() : MyClass<T,false>(/* chosen constructor args */) { etc; } 

    using MyClass<T,false>::MyClass<T,false>; 
}; 

आप सी ++ 11 नहीं है, तो आप using निर्माता विरासत उपयोग नहीं कर सकते हैं और आप अपने सभी कंस्ट्रक्टर्स redeclare और आधार वर्ग के साथ उनके तर्कों को आगे करना होगा।

यह उंगलियों से कीबोर्ड है, मेरे पास एक कंपाइलर आसान एटीएम नहीं है इसलिए मामूली वाक्यविन्यास गूंज कुछ हद तक संभव है।

+0

@jhill VS11 में यह संकलन नहीं कर सकता। मेरे पास constexpr के लिए कोई समर्थन – Ghita

+0

यह संकलन नहीं करता है: टेम्पलेट वर्ग MyClass { }; टेम्पलेट वर्ग MyClass:। सार्वजनिक MyClass { MyClass() {} }; – Ghita

1

आप एक डिफ़ॉल्ट पैरामीटर टिप्पणी में उल्लेख किया गया है के साथ समाधान के बाद से के रूप में

template < typename ...Whatever > 
class MyClass 
{ 
public: 
    static constexpr bool has_default_ctr = Something; 

    // I want this only if "has_default_ctr" is "true". 
    MyClass() 
    { 
     static_assert(has_default_ctr, "Not Default Constructible"); 
    } 

    //... 
}; 
1

के रूप में सरल कुछ कर सकते हैं, लेकिन मैं इसे कैसे करना है यह पता लगाने की काफी कुछ समय की जरूरत है (मेरे Enabler वर्ग को निजी बनाया है, जो काम नहीं करता है), यहाँ सुझाव दिया समाधान, मामले में किसी को भी इसके लिए लग रही है:

class MyClass { 
public: 
    // if constructor is supposed to be public, 
    // this helper class must be public as well! 
    struct Enabler {}; 

    template <class U = Enabler> 
    MyClass (std::enable_if_t<has_default_ctr, U> = Enabler {}) 
    { 
     // whatever 
    } 
}; 
0

यहाँ एक मैं हाल ही में उपयोग है। मुझे एक डिफ़ॉल्ट कन्स्ट्रक्टर के साथ एक क्लास टेम्पलेट की आवश्यकता होती है यदि उसके डेटा सदस्य डिफ़ॉल्ट कन्स्ट्रक्टर का समर्थन करते हैं, अन्यथा डिफ़ॉल्ट कन्स्ट्रक्टर को संकलित नहीं करना चाहिए।

वर्ग टेम्पलेट एक टेम्पलेट प्रकार पैरामीटर परिभाषित करता है, और वर्ग इस तरह के एक प्रकार का एक डेटा सदस्य (वंशानुक्रम का उपयोग एक प्रकार के रूप में भी इसे खाली baseclass अनुकूलन कर सकता है, आकर्षक हो सकता है) को परिभाषित करता है। डेटा सदस्य का डिफ़ॉल्ट कन्स्ट्रक्टर स्वचालित रूप से कक्षा के डिफ़ॉल्ट कन्स्ट्रक्टर द्वारा बुलाया जाता है। यदि डेटा सदस्य के प्रकार में डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है, तो संकलन विफल रहता है। अन्यथा यह सफल होता है। यहाँ कोड है:

#include <string> 
template <typename Data> 
class Demo 
{ 
    Data d_data; 

    public: 
     Demo() = default;  // OK when used and Data has a default 
           // constructor. 

     Demo(Data const &data) // Exampe of an additional constructor 
     : 
      d_data(data) 
     {} 

     // ... 
}; 

struct WithoutDefault 
{ 
    WithoutDefault(int) 
    {} 
}; 

int main() 
{ 
    Demo<std::string> withString; 
    // Demo<NoDefault> nope;    // won't compile 

    WithoutDefault nod(10); 
    Demo<WithoutDefault> nodefault(nod); // OK 
} 
संबंधित मुद्दे

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