टिप्पणी में उल्लेख किया है, आप पता लगा सकते हैं कि क्या एक ओवरलोड 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;
मैं पूछ सकता हूँ क्यों आप इसे ज़रूरत है? –
वस्तुओं के पते संकलित समय ज्ञात नहीं हैं। – Erik
यह संभव नहीं है: विचित्र रूप से पर्याप्त रूप से पर्याप्त 'constexpr' नहीं हो सकता है। लेकिन मैं ऐसी परिस्थिति की कल्पना नहीं कर सकता जिसमें एक 'कॉन्स्टेक्स एड्रेस' की आवश्यकता होगी। –