2012-01-21 11 views
5

हमारे पास जटिल टेम्पलेट वर्ग हैं जिनमें कुछ विधियां हैं जो कुछ नीतियों या प्रकारों के साथ काम नहीं करेंगे। इसलिए, जब हम उन प्रकारों का पता लगाते हैं (संकलन समय पर, प्रकार-गुणों का उपयोग करके) हम एक अच्छे संदेश के साथ एक स्थिर दावे को आग लगाते हैं।क्या मैं मैन्युअल टेम्पलेट तत्कालता से कुछ तरीकों को बाहर कर सकता हूं?

अब हम मैन्युअल टेम्पलेट इंस्टेंटेशन के बहुत सारे काम करते हैं। आंशिक रूप से ऐसा है कि तरीकों को जांचने के लिए विधियों को संकलक करने के लिए मजबूर किया जाता है। यह लाइब्रेरी उपयोगकर्ता के लिए संकलन समय भी कम कर देता है। समस्या यह है कि स्थैतिक दावे हमेशा निकाल दिए जाते हैं और इसके परिणामस्वरूप हम टेम्पलेट वर्ग को मैन्युअल रूप से प्रश्न में तुरंत चालू नहीं कर सकते हैं।

क्या इसके लिए कोई कामकाज है?

संपादित करें: यह स्पष्ट करने के लिए यहां एक उदाहरण (इस मामले में स्पष्ट इन्स्टेन्शियशन है someFunc1() पर विफल हो जाएगा:

// header 
template <typename T> 
class someClass 
{ 
    void someFunc() {} 
    void someFunc1() { static_assert(false, assertion_failed); } 
}; 

// source 
template someClass<int>; // Explicit instantiation 

EDIT2:। यहाँ एक और उदाहरण है इस बार आप देखने के लिए कि मैं क्या मतलब है कि यह संकलन कर सकते हैं। सबसे पहले सही दूर संकलन। कोड संकलन करना चाहिए। तब टिप्पणी हटाएं [2] और स्थिर अभिकथन सक्रिय होना चाहिए। अब [2] और टिप्पणी हटाएं [1]। The टिप्पणी बाहर स्थिर दावा वाई आग लग जाएगी क्योंकि आप स्पष्ट रूप से टेम्पलेट को तत्काल कर रहे हैं। मैं इसके साथ आने वाले लाभों के कारण स्पष्ट तत्कालता को हटाने से बचाना चाहता हूं (लाभ के लिए ऊपर देखें)।

namespace Loki 
{ 
    template<int> struct CompileTimeError; 
    template<> struct CompileTimeError<true> {}; 
} 

#define LOKI_STATIC_CHECK(expr, msg) \ 
    { Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

template <typename T> 
class foo 
{ 
public: 

    void func() {} 
    void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); } 
}; 

template foo<int>; 
//template foo<double>; // [1] 

int main() 
{ 
    foo<int> a; 
    a.func1(); 

    foo<double> b; 
    //b.func1(); //[2] 

    return 0; 
} 
+0

यह वर्णन से स्पष्ट नहीं है कि समस्या क्या है, लेकिन समस्या के दायरे से ऐसा लगता है कि enable_if आपके लिए है (http://www.boost.org/doc/libs/1_48_0/libs/utility/ enable_if.html) – bobah

+0

@ बोबाः यह बिल्कुल बुरा विचार नहीं है ... मैं इसे देख लूंगा। यदि आप एक साधारण उदाहरण तैयार कर सकते हैं जिसे मैं सत्यापित कर सकता हूं, तो मैं इसे उत्तर के रूप में चिह्नित करूंगा? – Samaursa

+1

मैं उन लोगों से सहमत हूं जो विवरण की कमी के बारे में शिकायत करते हैं। लेकिन वैसे भी, यह मेरे लिए एक घंटी बजती है: "समस्या यह है कि स्थिर दावे हमेशा निकाल दिए जाते हैं"। http://www.boost.org/doc/libs/1_48_0/doc/html/boost_staticassert.html#boost_staticassert.templates, अंतिम टिप्पणी: क्या यह समस्या आपके पास है? –

उत्तर

0

मैं enable_if का परीक्षण करने का अवसर प्राप्त नहीं किया bobah ने सुझाव दिया है, लेकिन मैं एक समाधान है कि बढ़ावा आवश्यकता नहीं है और के साथ आया था:

यहाँ ऐसा दिखाई दे सकता है कि कैसे की एक त्वरित उदाहरण है कि एक अच्छा हद तक अपने मूल आवश्यकता (मैं कहता हूँ अच्छा और नहीं पूर्ण, अंत में समझा जाएगा)

समाधान कोड पर एक डमी टेम्पलेट डाल करने के लिए है कि अगर कुछ चयनित तहत संकलित असफल हो जायेगी है संतुष्ट करता है प्रकार और है दूसरों के तहत ठीक है। तो:

struct dummyStruct {}; 

#define DUMMY_TEMP typename dummy 
#define DUMMY_PARAM dummyStruct 

namespace Loki 
{ 
    template<int> struct CompileTimeError; 
    template<> struct CompileTimeError<true> {}; 
} 

#define LOKI_STATIC_CHECK(expr, msg) \ 
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

template <typename T> 
class foo 
{ 
public: 

    void func() {} 
    template <typename T_Dummy> 
    void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); } 
}; 

template foo<int>; 
template foo<double>; // [1] 

int main() 
{ 
    foo<int> a; 
    a.func1<DUMMY_PARAM>(); 

    foo<double> b; 
    //b.func1<DUMMY_PARAM>(); //[2] - this is a static error 

    return 0; 
} 

मेरे टेम्पलेट कोड के सभी में, कार्यों की तरह (यानी लोगों को स्थिर है कि दावा है या कुछ प्रकार पर काम करते हैं और प्रकार लक्षण [जो मामले में एक चयन है का उपयोग करके दूसरों पर विफल हो सकता है विभिन्न प्रकार के लिए कई अलग-अलग कार्यों के]] ग्राहक से छिपे हुए हैं। तो मेरे कार्यान्वयन में, अतिरिक्त dummy parameter जोड़ना एक ठीक समझौता है।

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

2

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

मुझे लगता है कि आप सबसे अच्छा कर सकते हैं त्रुटि को लिंक करने के लिए त्रुटि को स्थानांतरित करें, जो स्थिर रूप से सुनिश्चित करेगा कि प्रोग्राम में कोड पथ नहीं है जो संभावित रूप से प्रतिबंधित फ़ंक्शन को कॉल कर सकता है, लेकिन त्रुटि संदेश बहुत उपयोगी नहीं होंगे किसी भी व्यक्ति को जो प्रतिबंध लगा रहा है उसके बारे में नहीं जानता है। वैसे भी, समाधान निषिद्ध सदस्य कार्यों में से एक विशेषज्ञता की घोषणा, लेकिन उनमें से परिभाषित नहीं है:

template<typename T> 
struct Foo { 
    void bar() { 
     std::cout << "bar\n"; 
    } 
    void baz() { 
     std:: cout << "baz\n"; 
    } 
}; 

template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail 

template struct Foo<int>; 
template struct Foo<char>; 

int main() { 
    Foo<int> f; 
    f.bar(); 
    // f.baz(); // uncommenting this line results in an ugly link time error 
    Foo<char> b; 
    b.bar(); 
    b.baz(); // works with Foo<char> 
} 

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

+1

अगर आप एक उदाहरण बना रहे हैं तो यह ठीक है। हमारे मामले में हम स्पष्ट तत्कालता का उपयोग कर रहे हैं जो समस्या का कारण बनता है (ऊपर संपादित देखें) – Samaursa

+0

किसी भी भविष्य के लिए भ्रम से बचने के लिए, मेरी टिप्पणी ऊपर _before_ संपादन के लिए है (जिसे मैंने कुछ संपादनों के साथ अपने प्रश्न को स्पष्ट करने से पहले बनाया था) – Samaursa

+0

+1 ** यह उत्तर होना चाहिए। ** थोड़ा अनावश्यक काम की आवश्यकता है लेकिन वितरित करता है :) – CodeAngry

1

enable_if सटीक टेम्पलेट विधियों के लक्ष्यीकरण के लिए एक लचीली तंत्र है, जो आप बाद में हो सकते हैं। उदाहरण:

#include <string> 
#include <iostream> 

#include <boost/utility.hpp> 
#include <boost/type_traits.hpp> 
#include <boost/static_assert.hpp> 

template <class T> class mywrapper 
{ 
    T _value; 

    template <class V> 
    typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value) 
    { 
    BOOST_STATIC_ASSERT(boost::is_scalar<V>::value); 
    std::cout << "scalar: " << value << std::endl; 
    } 

    template <class V> 
    typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value) 
    { 
    BOOST_STATIC_ASSERT(boost::is_compound<V>::value); 
    std::cout << "compound: " << value << std::endl; 
    } 

public: 
    mywrapper(T const& value):_value(value) { } 
    void printval() { printval_(_value); } 
}; 

template class mywrapper<int>; 
template class mywrapper<std::string>; 

int main() 
{ 
    mywrapper<int> ival(333); 
    mywrapper<std::string> sval("test"); 

    ival.printval(); 
    sval.printval(); 
    return 0; 
} 
+0

मेरे पास वर्तमान में 'बूस्ट' नहीं है, लेकिन क्या यह स्पष्ट तत्कालता के साथ भी काम करेगा? उदाहरण के लिए, 'int main() 'से पहले यदि आप' टेम्पलेट mywrapper डालते हैं; टेम्पलेट mywrapper ; 'और प्रत्येक कार्य में, आप यह सुनिश्चित करने के लिए एक स्थिर जोर देते हैं कि आप क्रमशः स्केलर और कंपाउंड प्रकारों के साथ काम कर रहे हैं; क्या यह संकलित होगा? – Samaursa

+0

स्थिर आवेषण और तत्काल – bobah

+0

के साथ उदाहरण अपडेट किया गया धन्यवाद bobah! जैसे ही मैं 'बूस्ट' प्राप्त कर सकता हूं, मैं इसका परीक्षण करूंगा। – Samaursa

3

आप दोनों नहीं कर सकते हैं: आप इन्स्टेन्शियशन और स्पष्ट प्रकार का दृष्टांत को रोकने के लिए एक स्थिर दावा नहीं कर सकते हैं! यह एक स्पष्ट विरोधाभास है। हालांकि, आप सशर्त रूप से कार्यक्षमता को शामिल कर सकते हैं, भले ही यह गर्दन में कुछ हद तक दर्द हो: यदि किसी निश्चित सदस्य फ़ंक्शन को कुछ प्रकार के लिए समर्थित नहीं माना जाता है, तो आप इस फ़ंक्शन को बेस क्लास में ले जा सकते हैं, जो सशर्त रूप से है । इस तरह आप एक स्थिर दावे का उपयोग नहीं करेंगे बल्कि सदस्य फ़ंक्शन को हटा दें। मुझे एहसास है कि यह दिलचस्प अन्य समस्याओं का परिचय देता है, उदा। सदस्य चर के स्थान के संबंध में, लेकिन मुझे लगता है कि संदर्भ में आप वर्णन कर रहे हैं कि यह सबसे अच्छा है जिसे आप प्राप्त कर सकते हैं।

template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base; 
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ }; 
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } }; 

template <typename T> 
struct Foo: foo_base<T> { /* .... */ }; 

template struct Foo<int>; // will have foo() 
template struct Foo<double>; // will not have foo() 
संबंधित मुद्दे

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