2015-01-30 9 views
7

के रूप में घोषणा का उपयोग कर using घोषणा के लिए मैं एसएफआईएनएई (या दूसरी तकनीक) का उपयोग कर सकता हूं जबकि निजी टेम्पलेट वर्ग से प्राप्त हो रहा है? बेहतर समझ के लिए कोड नीचे देखें:'उपयोग' का उपयोग एसएफआईएनएई

#include <iostream> 

struct S1 { 
    void f() { std::cout << "S1::f\n"; } 
}; 

struct S2 { 
    void f() { std::cout << "S2::f\n"; } 
    void g() { std::cout << "S2::g\n"; } 
}; 

template <class T> 
struct D : private T { 
    using T::f; 
    // using T::g; // need this only if T provides g() function 
}; 

int main() { 
    D<S1>().f(); // ok. Prints 'S1::f' 
    D<S2>().f(); // ok. Prints 'S2::f' 
    D<S2>().g(); // fail. But wants to be ok and prints 'S2::g' 
    return 0; 
} 

मैं कैसे वांछित व्यवहार (अगर यह संभव) तक पहुँच सकते हैं?

+0

संभावित डुप्लिकेट [क्या फ़ंक्शन के अस्तित्व की जांच के लिए सी ++ टेम्पलेट लिखना संभव है?] (Http://stackoverflow.com/questions/257288/is-it-possible-to-write-ac-template- टू-चेक-फॉर-ए-फ़ंक्शंस-अस्तित्व) – Klaus

+2

@ क्लोस नहीं, यह एक डुप्लिकेट नहीं है। यह प्रश्न आसानी से मान सकता है कि हमारे पास पहले से ही विशेषता है 'has_function_name_g '। अब क्या? आप इसे 'उपयोग' घोषणा पर कैसे लागू करते हैं? – Angew

उत्तर

4

सी ++ आंशिक टेम्पलेट विशेषज्ञता और SFINAE

के लिए decltype(void(&T::g)) का उपयोग
#include <iostream> 
#include <type_traits> 

struct S1 { 
    void f() { std::cout << "S1::f\n"; } 
}; 

struct S2 { 
    void f() { std::cout << "S2::f\n"; } 
    void g() { std::cout << "S2::g\n"; } 
}; 

template <class T, class V = void> 
struct D : private T { 
    using T::f; 
}; 

template <class T> 
struct D<T, decltype(void(&T::g))> : private T { 
    using T::f; 
    using T::g; // need this only if T provides g() function 
}; 

int main() { 
    D<S1>().f(); // ok. Prints 'S1::f' 
    D<S2>().f(); // ok. Prints 'S2::f' 
    D<S2>().g(); // ok. Prints 'S2::g' 
    return 0; 
} 

Live Demo


संपादित करें:

यह एक और दृष्टिकोण है कि अधिक लचीला है, लेकिन मैं पता नहीं कैसे करता है private virtual विरासत वास्तविक उपयोग मामलों के साथ काम करता है। अगर मुझे कोई समस्या हो सकती है (उदा। यूबी) तो कृपया मुझे बताएं।

#include <iostream> 
#include <type_traits> 

struct S1 { 
    void f() { std::cout << "S1::f\n"; } 
}; 

struct S2 { 
    void f() { std::cout << "S2::f\n"; } 
    void g() { std::cout << "S2::g\n"; } 
}; 

struct S3 { 
    void g() { std::cout << "S3::g\n"; } 
}; 

template <class T, class = void> 
struct D_f {}; 

template <class T> 
struct D_f<T, decltype(void(&T::f))> : private virtual T { 
    using T::f; 
}; 

template <class T, class = void> 
struct D_g {}; 

template <class T> 
struct D_g<T, decltype(void(&T::g))> : private virtual T { 
    using T::g; 
}; 

template <class T> 
struct D : D_f<T>, D_g<T> { 
}; 


int main() { 
    D<S1>().f(); 
    D<S2>().f(); 
    D<S2>().g(); 
    D<S3>().g(); 
    return 0; 
} 

Live Demo

+1

हालांकि यह अच्छी तरह से स्केल नहीं करता है। उन कार्यों के लिए जो उपलब्ध हो सकते हैं या नहीं भी हो सकते हैं, आपको 2 ** एन कक्षा परिभाषाओं का जादू करना होगा। – hvd

+0

@ ब्रायन चेन क्या मुख्य डी कक्षा टेम्पलेट के अंदर परिवर्तन को सीमित करना संभव है, यानी टी के प्रकार का उपयोग करने के बिना 'टी :: एफ;' का उपयोग करके कोड के दोहराव के बिना? – alexolut

5

ब्रायन चेन के जवाब यह है कि भद्दा दिखता है, लेकिन यह आसान कई जांच के विस्तार करने के लिए बनाता है, और कोड कि D<type-with-f> और D<type-without-f> के बीच साझा किया गया है डुप्लिकेट करने की आवश्यकता नहीं है का एक प्रकार, उपयोग करने के लिए है एक विरासत श्रृंखला, जहां प्रत्येक चरण एक अतिरिक्त सदस्य की जांच करता है। उपयुक्त होने पर केवल एकमात्र डुप्लिकेशंस कन्स्ट्रक्टर की विरासत है।

struct A { 
    void f() { } 
    void g() { } 
    void i() { } 
}; 

// The generic case. D<T, char[N]> simply provides what D<T, char[N+1]> provides. 
template <typename T, typename U = char[1]> 
struct D : D<T, char[sizeof(U) + 1]> { 
    using D<T, char[sizeof(U) + 1]>::D; 
}; 

// The end of the chain. This is where T gets inherited. It declares all of its own 
// specialisations as its friends, so that they can access other members of T. 
template <typename T> 
struct D<T, char[6]> : private T { 
    template <typename, typename> 
    friend struct D; 

    D(int) { } 
    void fun() { } 
}; 

// Check for T::f. 
template <typename T> 
struct D<T, char[2 + !sizeof(&T::f)]> : D<T, char[3]> { 
    using D<T, char[3]>::D; 
    using T::f; 
}; 

// Check for T::g. 
template <typename T> 
struct D<T, char[3 + !sizeof(&T::g)]> : D<T, char[4]> { 
    using D<T, char[4]>::D; 
    using T::g; 
}; 

// Check for T::h. 
template <typename T> 
struct D<T, char[4 + !sizeof(&T::h)]> : D<T, char[5]> { 
    using D<T, char[5]>::D; 
    using T::h; 
}; 

// Check for T::i. 
template <typename T> 
struct D<T, char[5 + !sizeof(&T::i)]> : D<T, char[6]> { 
    using D<T, char[6]>::D; 
    using T::i; 
}; 

int main() { 
    D<A> d = 4; // ok: verify that constructors got inherited 
    // A &a = d; // error: verify that inheritance of A is private 
    d.f(); // ok: verify that f got inherited 
    d.g(); // ok: verify that g got inherited 
    // d.h(); // error: verify that h is not available 
    d.i(); // ok: verify that i got inherited 
    d.fun(); // ok: verify that the inheritance chain didn't get broken 
} 

नोट: बजाय &T::f जाँच की, आप के बजाय std::declval<T>().f() साथ कुछ करने के लिए कर सकते हैं। पूर्व अधिभारित कार्यों को संभाल नहीं सकता है।

+0

हम्म, मैंने 'std :: integral_constant' का उपयोग किया होगा, लेकिन बहुत अच्छा है। –

+0

@ टी.सी. हे, यह उन चीजों में से एक है जो मुझे पता है, लेकिन किसी भी तरह से कभी खत्म नहीं होता है, क्योंकि जब भी यह उपयोगी हो सकता है, मैं पहले से ही अपने दिमाग में एक समाधान के साथ समाप्त हो गया है जिसकी आवश्यकता नहीं है। :) – hvd

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