2013-02-13 10 views
16

मुझे फ़ंक्शन के कॉन्स्टेक्स पते को लिखने की आवश्यकता है, लेकिन मुझे यह असंभव लगता है। यदि संभव है तो किस प्रकार, क्या कोई जानता है?पता() को constexpr फ़ंक्शन के रूप में कार्यान्वित किया जा सकता है?

cppreference.com पर में एक संदर्भ कार्यान्वयन:

template< class T > 
T* addressof(T& arg) 
{ 
    return reinterpret_cast<T*>(
      &const_cast<char&>(
       reinterpret_cast<const volatile char&>(arg) 
      ) 
     ); 
} 

reinterpret_cast (इसी तरह जीसीसी कार्यान्वयन के लिए) का उपयोग करता है, तो यह काम नहीं चलेगा। मैं देख सकता हूं कि नवीनतम सी ++ मानक मसौदा, N3485 को उस पते की आवश्यकता नहीं है() constexpr होने के बावजूद कई फ़ंक्शन हेडर < उपयोगिता > हाल ही में बेन को कॉन्स्टेक्स में अपग्रेड किया गया है।

एक संभव है, हालांकि इसके लिए बहुत समझाने या उपयोगी नहीं यूज-केस होगा:

constexpr MyType m; 
constexpr MyType const* p = &m;   // this works today 
constexpr MyType const* p = addressof(m); // this is my question 

कल्पना कीजिए कि MyType ऑपरेटर & अतिभारित किया है।

+0

मैं पूछ सकता हूँ क्यों आप इसे ज़रूरत है? –

+4

वस्तुओं के पते संकलित समय ज्ञात नहीं हैं। – Erik

+0

यह संभव नहीं है: विचित्र रूप से पर्याप्त रूप से पर्याप्त 'constexpr' नहीं हो सकता है। लेकिन मैं ऐसी परिस्थिति की कल्पना नहीं कर सकता जिसमें एक 'कॉन्स्टेक्स एड्रेस' की आवश्यकता होगी। –

उत्तर

1

एक आंशिक कामकाज union रैपर के भीतर ऐसी किसी भी वस्तु को परिभाषित करना है, और union पर पॉइंटर्स के आसपास पास करना है। रैपर के सूचक को आसानी से प्रकार के संदर्भ में परिवर्तित किया जा सकता है। सूचक अंकगणित रैपर के सरणी पर काम करना चाहिए। लेकिन मुझे अभी भी operator& ओवरलोडेड प्रकार के साथ पॉइंटर प्राप्त करने का कोई तरीका नहीं दिख रहा है।

union केवल एक सदस्य की आवश्यकता है; struct अभ्यास में काम करेगा लेकिन सिद्धांत रूप में एक कार्यान्वयन शुरुआत में पैडिंग जोड़ सकता है। ऐसा नहीं है कि पैडिंग वास्तव में एक फर्क पड़ता है, अगर आप निरंतर अभिव्यक्ति में MyType * प्राप्त नहीं कर सकते हैं।

template< typename t > 
union storage_wrapper 
    { t obj; }; 

constexpr storage_wrapper<MyType> m{{ args_to_MyType_constructor }}; 
constexpr storage_wrapper<MyType> *p = &m; // not overloaded 
8

टिप्पणी में उल्लेख किया है, आप पता लगा सकते हैं कि क्या एक ओवरलोड operator& SFINAE का उपयोग कर उपलब्ध है। और जैसा कि Potatoswatter टिप्पणी में बताते हैं, इन तीन अलग-अलग चेकों होने की जरूरत:

1) क्या x.operator&()

2 स्वीकार किया जाता है) क्या operator&(x) स्वीकार किया जाता है

पहले दो दो तरीके एक उपयोगकर्ता हैं -प्रोवाइड operator& परिभाषित किया जा सकता है।

3) क्या &x

यह तीसरा जांच आवश्यक है, क्योंकि x.operator&() को अस्वीकार कर दिया जा सकता है क्योंकि operator& मौजूद है स्वीकार किया जाता है, लेकिन यह निजी है। उस स्थिति में, &x मान्य नहीं है।

ये चेक sizeof(f(std::declval<T>())) की जांच करके कार्यान्वित किए जा सकते हैं, जहां f इस तरह से ओवरलोड किया गया है कि वापसी का प्रकार इस बात पर निर्भर करता है कि T चेक पास करता है या नहीं।

namespace addressof_helper { 
    template <typename T> 
    static char (&checkaddressof(...))[1]; 

    template <typename T> 
    static char (&checkaddressof(T &&, typename std::remove_reference<decltype(&std::declval<T &>())>::type * = 0))[2]; 

    template <typename T> 
    static char (&checknonmember(...))[1]; 

    template <typename T> 
    static char (&checknonmember(T &&, typename std::remove_reference<decltype(operator&(std::declval<T &>()))>::type * = 0))[2]; 

    template <typename T> 
    static char (&checkmember(...))[1]; 

    template <typename T> 
    static char (&checkmember(T &&, typename std::remove_reference<decltype(std::declval<T &>().operator&())>::type * = 0))[2]; 
} 

फिर आप addressof की जो कार्यान्वयन उपयोग करने के लिए चयन करने के लिए इन सहायक कार्यों का उपयोग कर सकते हैं:

template <typename T> 
constexpr typename std::enable_if< 
    sizeof(addressof_helper::checkaddressof<T>(std::declval<T>())) == 2 
    && sizeof(addressof_helper::checknonmember<T>(std::declval<T>())) == 1 
    && sizeof(addressof_helper::checkmember<T>(std::declval<T>())) == 1, 
    T *>::type addressof(T &t) { 
    return &t; 
} 

template <typename T> 
/* no constexpr */ typename std::enable_if< 
    sizeof(addressof_helper::checkaddressof<T>(std::declval<T>())) == 1 
    || sizeof(addressof_helper::checknonmember<T>(std::declval<T>())) == 2 
    || sizeof(addressof_helper::checkmember<T>(std::declval<T>())) == 2, 
    T *>::type addressof(T &t) { 
    return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t))); 
} 

यह अनुमति देता है addressof इतने लंबे समय के रूप में operator& ओवरलोड न हो जाए निरंतर भाव में इस्तेमाल किया जाएगा।यदि यह ओवरलोड हो गया है, तो ऐसा लगता है कि एक ऐसे रूप में पते को विश्वसनीय रूप से प्राप्त करने का कोई तरीका नहीं है जो निरंतर अभिव्यक्ति में प्रयोग योग्य है।

ध्यान दें कि जीसीसी 4.7 इस addressof कार्यान्वयन के मामलों को अस्वीकार करता है जहां इसे काम करना चाहिए। जीसीसी 4.8 और उच्चतर काम, जैसा कि झुकाव करता है।

मुझे लगता है कि मेरा उत्तर के पिछले संस्करण में एक सहायक समारोह के पास भेज addressof की एक एकल कार्यान्वयन के लिए इस्तेमाल किया है, लेकिन मैं हाल ही में अवगत कराया गया था कि यह एक अच्छा विचार के रूप में यह आसानी से ओडीआर उल्लंघन का कारण बन सकता है, तो addressof<X> है नहीं है, कुछ अनुवाद X के लिए कई अनुवाद इकाइयों में उपयोग किया जाता है, जिनमें से कुछ X परिभाषित किया गया है, और इनमें से कुछ X अधूरा है। दो अलग-अलग कार्यों के कारण उस समस्या से बचा जाता है।

केवल शेष समस्या अगर addressof<X>X के कस्टम operator& की परिभाषा से पहले एक अनुवाद इकाई में प्रयोग किया जाता है कि यह विफल हो सकता है। यह उम्मीद है कि यह दुर्लभ हो सकता है कि यह अभ्यास में कोई समस्या नहीं है। समझदार उदाहरण के लिए

testcases:

class A { } a; 
class B { private: B *operator&(); } b; 
class C { C *operator&(); } c; 
class D { } d; 
D *operator&(D &); 
extern class E e; 

int main() { 
    constexpr A *pa = addressof(a); 
    /* no constexpr */ B *pb = addressof(b); 
    /* no constexpr */ C *pc = addressof(c); 
    /* no constexpr */ D *pd = addressof(d); 
    constexpr E *pe = addressof(e); 
} 

class E { } e; 
+0

एसएफआईएनएई त्रुटिपूर्ण है। यह एक गैर-सदस्य या निजी सदस्य अधिभार नहीं पकड़ता है। मेरी टिप्पणी देखें। – Potatoswatter

+0

बिल्टिन '&' ऑपरेटर उपयोग योग्य नहीं है अगर ओवरलोड पहुंच योग्य नहीं है। – Potatoswatter

+0

@Potatoswatter अपडेट किया गया, क्या यह आपके लिए बेहतर दिखता है? – hvd

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

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