2010-04-23 20 views
35

मैं refuting the notion के बाद धारा 13.5 पर विचार कर रहा था कि अंतर्निहित ऑपरेटरों अधिभार संकल्प में भाग नहीं लेते हैं, और ध्यान दिया कि operator->* पर कोई अनुभाग नहीं है। यह सिर्फ एक सामान्य बाइनरी ऑपरेटर है।नि: शुल्क ऑपरेटर हैं -> * बुराई अधिभार?

इसके भाइयों, operator->, operator*, और operator[], सभी को गैर स्थैतिक सदस्य कार्य होने की आवश्यकता है। यह एक ऑब्जेक्ट से संदर्भ प्राप्त करने के लिए प्रयुक्त आमतौर पर पर एक फ्री फ़ंक्शन अधिभार की परिभाषा को रोकता है। लेकिन असामान्य operator->* छोड़ा गया है।

विशेष रूप से, operator[] में कई समानताएं हैं। यह द्विआधारी है (उन्हें एन-आरी बनाने के लिए एक सुनहरा मौका छूट गया), और यह बाईं ओर किसी प्रकार का कंटेनर स्वीकार करता है और दाईं ओर किसी प्रकार का लोकेटर स्वीकार करता है। इसका विशेष नियम खंड, 13.5.5, मुक्त कार्यों को छोड़कर किसी वास्तविक प्रभाव का प्रतीत नहीं होता है। (और है कि प्रतिबंध भी commutativity के लिए समर्थन का निवारण होता!)

तो, उदाहरण के लिए, इस perfectly legal है:

#include <utility> 
#include <iostream> 
using namespace std; 

template< class T > 
T & 
operator->*(pair<T,T> &l, bool r) 
    { return r? l.second : l.first; } 

template< class T > 
T & operator->*(bool l, pair<T,T> &r) { return r->*l; } 

int main() { 
     pair<int, int> y(5, 6); 
     y->*(0) = 7; 
     y->*0->*y = 8; // evaluates to 7->*y = y.second 
     cerr << y.first << " " << y.second << endl; 
} 

इसे इस्तेमाल करता है खोजने के लिए आसान है, लेकिन वैकल्पिक वाक्य रचना है कि बुरा नहीं हो जाता है। उदाहरण के लिए, vector के लिए अनुक्रमित बढ़ाया:

v->*matrix_width[2][5] = x; // ->* not hopelessly out of place 

my_indexer<2> m(v, dim); // my_indexer being the type of (v->*width) 
m[2][5] = x; // it is probably more practical to slice just once 

मानक समिति इसे रोकने के लिए भूल गए, था यह बहुत परेशान करने के लिए बदसूरत माना जाता है, या वहाँ वास्तविक दुनिया उपयोग के मामलों रहे हैं?

+0

एक डेटा बिंदु: Coneau (http://www.comeaucomputing.com/tryitout/) को खारिज कर दिया अपने कोड के बाद भी मैं 'को हटा दिया है ' और पहली ऑपरेटर: 'त्रुटि: कोई ऑपरेटर" -> * "इन ऑपरेटरों से मेल खाता है – sbi

+1

@ एसबीआई: कॉमौ पहली जगह थी जहां मैं कोशिश करने और देखने के लिए गया था। मेरे पास अभी भी वह टैब खुल गया है ... जीसीसी 4.5 पर स्विच करने से पहले मैंने जो कोड डाला था वह" स्ट्रक्चर एक्स {इंट वाई;}; था int और ope rator -> * (x & l, int r) {वापसी l.y; } शून्य एफ() { x क्यू; int और i = q -> * 3; } "- और यह मुख्य उदाहरण के लिए सफलता देता है जो पहले टाइप_ट्रेट्स पर निर्भर करता है सब कुछ निर्भर करता है। – Potatoswatter

+0

मुझे नहीं पता कि ऑपरेटर -> * को इस तरह अधिभारित क्यों किया जा सकता है, लेकिन यह निश्चित रूप से हेला बदसूरत दिखता है! मैं चाहता था कॉमा ओवरलोडिंग के समान कारण से दूर रहें - यह अंतर्ज्ञानी सी ++ की तरह दिखता नहीं है। – AshleysBrain

उत्तर

2

थोड़ा सा गुगलिंग, मुझे लोगों के अधिक उदाहरण मिलते हैं कि क्या operator->* वास्तविक सुझावों से पहले कभी भी उपयोग किया जाता है।

कुछ जोड़े स्थान T &A::operator->*(T B::*) का सुझाव देते हैं। यह सुनिश्चित नहीं है कि यह डिज़ाइनर के इरादे या गलतफहमी को दर्शाता है कि T &A::operator->*(T A::*) एक अंतर्निहित है। वास्तव में मेरे प्रश्न से संबंधित नहीं है, लेकिन ऑनलाइन चर्चा & साहित्य में मिली गहराई का विचार देता है।

"डी & ई 11.5.4" का उल्लेख था जो मुझे लगता है कि सी ++ का डिजाइन और विकास है। शायद इसमें एक संकेत है। अन्यथा, मैं बस यह निष्कर्ष निकालना चाहता हूं कि यह बेकार बेकार है जो मानकीकरण द्वारा अनदेखा किया गया था, और अधिकांश अन्य भी।

संपादित करें डी & ई उद्धरण के पेस्ट के लिए नीचे देखें।

इस मात्रात्मक रूप से रखने के लिए, ->* सबसे सख्त बाध्यकारी ऑपरेटर है जिसे एक मुक्त फ़ंक्शन द्वारा ओवरलोड किया जा सकता है। सभी पोस्टफिक्स-अभिव्यक्ति और यूनरी ऑपरेटरों के अधिभारों को नॉनस्टैटिक सदस्य फ़ंक्शन हस्ताक्षर की आवश्यकता होती है। यूनरी ऑपरेटरों के बाद अगली प्राथमिकता सी-स्टाइल कास्ट है, जिसे रूपांतरण कार्यों (operator type()) के अनुरूप कहा जा सकता है, जो निःशुल्क फ़ंक्शंस भी नहीं हो सकता है। फिर ->* आता है, फिर गुणा। ->*[] या % की तरह हो सकता था, वे किसी भी तरह से जा सकते थे, और उन्होंने EEEEEEVIL का मार्ग चुना।

+0

क्या यह आपके प्रश्न का उत्तर देता है? मुझे नहीं पता था कि हम अपना जवाब स्वीकार कर सकते हैं :) –

+0

@ विज़ेंट: मैंने आपका स्वीकार करने पर विचार किया है, लेकिन यह अभी भी गलती से कहता है कि गैर-सदस्य 'ऑपरेटर->' की अनुमति है और 'ऑपरेटर' को अनुमति देने के लिए तर्क (या 2) = 'लेकिन टिप्पणियों में 'ऑपरेटर =' को अस्वीकार कर दिया गया था। और मैं वास्तव में (डी) समझौते की तलाश नहीं कर रहा था, सवाल यह था कि क्या मानक समिति इसे रोकने के लिए भूल गई थी, क्या इसे परेशान करने के लिए बहुत बदसूरत माना जाता था, या असली दुनिया के उपयोग के मामले हैं? *, जो कि एक बात है निष्कर्षों में से किसी एक का समर्थन करने के लिए कुछ संदर्भ या सबूत ढूंढना। – Potatoswatter

+0

मैं इस आत्म-उत्तर से वास्तव में खुश नहीं हूं, लेकिन मुझे एक डाउनवोट द्वारा प्रेरित किया गया था (ऐसा लगता है कि ओपन-एंडेड प्रश्न इतने लंबे समय तक अनुत्तरित छोड़ दिया जा सकता है) और ऐसा लगता है कि साक्ष्य की कमी है, जो समर्थन करेगा निष्कर्ष कि इसे अनदेखा किया गया था। – Potatoswatter

1

मानक (कार्यकारी ड्राफ्ट 2010-02-16, § 5.5) का कहना है:

The result of an ->* expression is an lvalue only if its second operand is a pointer to data member. If the second operand is the null pointer to member value (4.11), the behavior is undefined.

आप इस व्यवहार को होने के लिए अच्छी तरह से परिभाषित कर सकते हैं। उदाहरण के लिए, जांचें कि यह एक शून्य सूचक है और इस स्थिति को संभाल लें। इसलिए मैं मानता हूं कि मानक के लिए यह सही निर्णय है -> * ओवरलोडिंग।

+2

क्लॉज 5 ओवरलोड पर लागू नहीं होता है। उदाहरण के लिए, 'ऑपरेटर /' ओवरलोड अपने दूसरे ऑपरेंड के लिए व्यवहार को परिभाषित कर सकता है, और आप कानूनी रूप से इसका उपयोग कर सकते हैं। – Potatoswatter

6

मैं आपसे सहमत हूं कि मानक पर एक असंगतता है, यह गैर-सदस्य कार्यों के साथ operator[] ओवरलोडिंग की अनुमति नहीं देता है और इसे operator->* के लिए अनुमति देता है। मेरे दृष्टिकोण के लिए operator[]operator->* के रूप में सरणी है जो structs/classes (एक गेटर) है। एक सरणी के सदस्य एक इंडेक्स का उपयोग कर चुने जाते हैं। एक संरचना के सदस्य सदस्य पॉइंटर्स का उपयोग कर चुने जाते हैं।

सबसे खराब है कि हम operator[] के बजाय ->* उपयोग करने के लिए तत्व

int& operator->*(Array& lhs, int i); 

Array a; 

a ->* 2 = 10; 

की तरह एक सरणी वहाँ भी है एक और संभव बेतरतीबी प्राप्त करने के लिए परीक्षा जा सकता है। हम operator+= और फॉर्म @= के सभी ऑपरेटर को अधिभारित करने के लिए गैर सदस्य फ़ंक्शन का उपयोग कर सकते हैं) और हम इसे operator= के लिए नहीं कर सकते हैं।

मैं वास्तव में नहीं जानता कि निम्नलिखित कानूनी

struct X { 
    int val; 
    explicit X(int i) : val(i) {} 
}; 
struct Z { 
    int val; 
    explicit Z(int i) : val(i) {} 
}; 
Z& operator+=(Z& lhs, const X& rhs) { 
    lhs.val+=rhs.val; 
    return lhs; 
} 

Z z(2); 
X x(3); 
z += x; 

बनाने के लिए तर्क और मना

Z& operator=(Z& lhs, const X& rhs) { 
    lhs.val=i; 
    return lhs; 
} 

z = x; 

आपके सवाल का जवाब नहीं करने के लिए क्षमा करें, लेकिन और भी अधिक भ्रम की स्थिति को जोड़ने है क्या।

+1

'ऑपरेटर -> 'और' ऑपरेटर @ = 'सदस्य कार्य होना चाहिए। नि: शुल्क फ़ंक्शंस आपके कंपाइलर द्वारा समर्थित हो सकते हैं, लेकिन यह निश्चित रूप से गैर मानक है। – Potatoswatter

+0

ऑपरेटर @ = गैर-सदस्य द्वारा ओवरलोड किया जा सकता है कार्य। मानक देखें। –

+2

§13.5.3 असाइनमेंट ऑपरेटर के बीच अंतर नहीं करता है। यह कहता है "एक असाइनमेंट ऑपरेटर एक गैर स्थैतिक मेम्ब द्वारा कार्यान्वित किया जाएगा एर एक बिल्कुल पैरामीटर के साथ काम करता है। "§5.17 कहता है" कई असाइनमेंट ऑपरेटर हैं, जिनमें से सभी समूह दाएं से बाएं हैं। "जब तक कुछ ऐसा नहीं होता है, तो 'ऑपरेटर =' विशेष नहीं होना चाहिए। – Potatoswatter

13

सबसे अच्छा उदाहरण मुझे पता है कि Boost.Phoenix है, जो इस ऑपरेटर को आलसी सदस्य पहुंच को लागू करने के लिए अधिभारित करता है।

(arg1 % 2 == 1)  // this expression evaluates to an actor 
       (3); // returns true since 3 % 2 == 1 

// these actors can also be passed to standard algorithms: 
std::find_if(c.begin(), c.end(), arg1 % 2 == 1); 
// returns iterator to the first odd element of c 

यह operator% और operator== अधिक भार से ऊपर को प्राप्त होता है:

फीनिक्स के साथ अपरिचित उन लोगों के लिए है, यह इमारत अभिनेताओं (या समारोह वस्तुओं) कि सामान्य भाव की तरह लग रही के लिए एक सर्वोच्च गंधा पुस्तकालय है। - अभिनेता arg1 पर लागू ये ऑपरेटर एक और अभिनेता लौटते हैं। भाव की सीमा जो इस तरह से बनाया जा सकता है चरम है:

// print each element in c, noting its value relative to 5: 
std::for_each(c.begin(), c.end(), 
    if_(arg1 > 5) 
    [ 
    cout << arg1 << " > 5\n" 
    ] 
    .else_ 
    [ 
    if_(arg1 == 5) 
    [ 
     cout << arg1 << " == 5\n" 
    ] 
    .else_ 
    [ 
     cout << arg1 << " < 5\n" 
    ] 
    ] 
); 

के बाद आप कुछ समय के लिए फीनिक्स का उपयोग कर (जो आपने कभी वापस नहीं) आप कुछ इस तरह की कोशिश करेंगे रहे हैं:

typedef std::vector<MyObj> container; 
container c; 
//... 
container::iterator inv = std::find_if(c.begin(), c.end(), arg1.ValidStateBit); 
std::cout << "A MyObj was invalid: " << inv->Id() << std::endl; 

जो असफल हो जाएगा, निश्चित रूप से फीनिक्स के कलाकारों के पास सदस्य ValidStateBit नहीं है। फीनिक्स operator->* अधिक भार से इस के आसपास हो जाता है:

(arg1 ->* &MyObj::ValidStateBit)    // evaluates to an actor 
           (validMyObj); // returns true 

// used in your algorithm: 
container::iterator inv = std::find_if(c.begin(), c.end(), 
     (arg1 ->* &MyObj::ValidStateBit) ); 

operator->* के तर्क हैं:

  • एलएचएस: लौटने MyObj *
  • आरएचएस एक अभिनेता: एक सदस्य के पता

यह एक रिटर्न देता है अभिनेता जो एलएचएस का मूल्यांकन करता है और इसमें निर्दिष्ट सदस्य की तलाश करता है।(एनबी: आप वास्तव में, वास्तव में यह सुनिश्चित करना चाहते हैं कि arg1MyObj * लौटाता है - जब तक आपको फीनिक्स में कुछ गड़बड़ न हो, तब तक आपको एक विशाल टेम्पलेट त्रुटि दिखाई नहीं दे रही है। इस छोटे कार्यक्रम ने 76,738 दर्द दर्द (बूस्ट 1.54, जीसीसी 4.6) उत्पन्न किया:

#include <boost/phoenix.hpp> 
using boost::phoenix::placeholders::arg1; 

struct C { int m; }; 
struct D { int n; }; 

int main() { 
    (arg1 ->* &D::n) (new C); 
    return 0; 
} 
+0

बढ़िया, साझा करने के लिए धन्यवाद! हालांकि यह उपयोग एक कैननिकल सदस्य समारोह के रूप में कार्यान्वयन का सुझाव देता है, जबकि प्रश्न गैर-सदस्य (मुक्त) कार्यों के बारे में अधिक विशेष रूप से है। – Potatoswatter

+1

मैंने चेक किया: बूस्ट कार्यान्वयन एक गैर-सदस्य फ़ंक्शन का उपयोग एक अलग, एंटी-एडीएल नेमस्पेस में करता है। यह शायद अन्य ऑपरेटरों के साथ सामान्य सर्वोत्तम अभ्यास और एकरूपता के लिए किया जाता है। – Potatoswatter

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