2010-02-18 12 views
5

मैं की तरह एक समारोह है, (। संदर्भ द्वारा अस्थायी लौटने के बारे में परवाह नहीं करते कृपया यह समस्या समझाने के लिए सिर्फ एक उदाहरण है)"foo <T>" से "स्थिरांक foo <const T>" में कनवर्ट कर रहा - सी ++

const foo<const int>& get_const() 
{ 
    foo<int> f; 
    return f; 
} 

यह स्पष्ट रूप से संकलित नहीं होगा। मैं यह सुनिश्चित करने के लिए एक तरीका ढूंढ रहा हूं कि कॉलर foo के T को नहीं बदलेगा। मैं यह कैसे सुनिश्चित कर सकता हूं?

मैंने boost::shared_ptr के लिए समान व्यवहार देखा है। shared_ptr<T> परिवर्तनीय है const shared_ptr<const T>। मैं यह नहीं समझ सका कि यह कैसे कर रहा है।

कोई भी मदद महान होगी।

+0

आप शायद यह सुनिश्चित करने की कोशिश कर रहे हैं कि कॉलर foo के * f * को नहीं बदलेंगे। –

उत्तर

0

अगर मैं गलत नहीं हूँ, boost::shared_ptr कार्यान्वयन एक गैर स्पष्ट निर्माता है कि एक तर्क के रूप में एक const T& संदर्भ लेता है और फिर आरएचएस के सूचक पर एक const_cast का उपयोग करता const दूर करने के लिए, उन दोनों के बीच निहित रूपांतरण के लिए अनुमति देता है।

कुछ इस तरह:

shared_ptr(const shared_ptr<const T>& r) : ptr(const_cast<T*>(r.ptr)) {} 

कि क्या आप के लिए देख रहे हैं?

+0

'const_cast' == मेरे लिए लाल हेरिंग :) ओपी कुछ ऐसा ढूंढ रहा है जो वास्तव में विपरीत है (जो अधिक प्राकृतिक है)। –

1

कि फू मान लिया जाये कि कुछ इस तरह परिभाषित किया गया है:

template<typename T> class Foo 
{ 
public: 
    Foo(const T& value) : m_value(value) { } 
    const T& getValue() const { return m_value; } 
    void setValue(const T& value) { m_value = value; } 
private: 
    T m_value; 
}; 

फिर, यह सुनिश्चित करने के फू के ग्राहकों m_value को संशोधित नहीं में (मुझे लगता है कि यह है कि क्या द्वारा "मैं एक रहा हूँ मतलब है कॉल करने के लिए सुनिश्चित करें foo की टी ") नहीं बदलेगा तरह, आप अपने टेम्पलेट पैरामीटर के बजाय const-अर्हता प्राप्त करने के फू वस्तु की जरूरत है, यानी

Foo<int> x(1); 
x.setValue(2); // OK 
const Foo<int> y(1); 
y.setValue(2); // does not compile 

इसलिए, अपने get_foo समारोह एक const Foo<T>&, नहीं एक लौटना चाहिए const Foo<const T>&

यहाँ एक पूर्ण, compilable उदाहरण है:

#include <iostream> 

template<typename T> class Foo 
{ 
public: 
    Foo(const T& value) : m_value(value) { } 
    const T& getValue() const { return m_value; } 
    void setValue(const T& value) { m_value = value; } 
private: 
    T m_value; 
}; 

template<class T> class Owner 
{ 
public: 
    Owner(const T& value) : m_foo(value) { } 
    Foo<T>& getFoo() { return m_foo; } 
    const Foo<T>& getConstFoo() const { return m_foo; } 

private: 
    Foo<T> m_foo; 
}; 


int main(int argc, char** argv) 
{ 
    Owner<int> x(1); 
    x.getFoo().setValue(2); 
    // x.getConstFoo().setValue(3); // will not compile 
} 
+0

हालांकि यह एक अच्छा जवाब है, ऐसे मामले हैं जब 'const foo 'वास्तव में आवश्यक हो सकता है, खासकर यदि' टी' एक सूचक प्रकार है या यदि foo 't *' संग्रहीत करता है। –

+0

@ टाइटलर सहमत हुए, ओपी कुछ हद तक अस्पष्ट था - जबकि यह पूछता है कि Foo को Foo में कैसे परिवर्तित किया जाए, यह भी कहता है, "मैं यह सुनिश्चित करने के लिए एक तरीका ढूंढ रहा हूं कि कॉलर्स टी के फू को नहीं बदलेगा", जो कि है मेरा जवाब फू ऑब्जेक्ट को स्वयं-योग्यता प्राप्त करने का लक्ष्य है। –

+0

उत्तर के लिए धन्यवाद। मैं देख रहा हूं कि @ टायलर ने क्या उल्लेख किया है। –

9

संकलक देखता foo<T> और foo<const T> दो पूरी तरह से अलग और असंबंधित प्रकार के रूप में, तो foo वर्ग किसी भी अन्य रूपांतरण के साथ के रूप में स्पष्ट रूप से इस समर्थन की जरूरत है। यदि आपके पास foo कक्षा पर नियंत्रण है, तो आपको एक प्रतिलिपि बनाने वाला या एक निहित रूपांतरण ऑपरेटर (या दोनों) प्रदान करना होगा।

template<typename T> 
class foo 
{ 
public: 

    // Regular constructor 
    foo(T t) : t(t) {} 

    // Copy constructor (works for any type S convertable to T, in particular S = non-const T if T is const) 
    // Remember that foo<T> and foo<S> are unrelated, so the accessor method must be used here 
    template<typename S> foo (const foo<S>& copy) : t(copy.getT()) {} 

    // Accessor 
    T getT() const { return t; } 

    // Conversion operator 
    operator foo<const T>() const { return foo<const T>(t); } 

private: 

    T t; 
}; 
+0

ग्रेट। बहुत बहुत धन्यवाद। –

0

सबसे पहले, आप संदर्भ द्वारा स्थानीय वस्तु वापस कर रहे हैं ... यह अच्छा नहीं है।

foo और foo दो अलग-अलग प्रकार हैं इसलिए आपको उन्हें स्पष्ट रूप से रूपांतरित करने के लिए कोड (रूपांतरण निर्माता) लिखना होगा।

जैसे आप चाहते हैं पाने के लिए, इस पर विचार करें:

template <typename T> 
struct foo {T* t;}; 

const foo<int>& get_const(const foo<int>& f) { 
    return f; 
} 

foo<int> f; 
const foo<int>& cf = get_const(f); 
f.t = 0; // ok, f is not const 
*cf.t = 0; // ok because cf.t is const but what cf.t points to is not 
cf.t = 0; // compiler error cf.t is const and cannot be lvalue 

foo<int>& cf = get_const(f); // compiler error, cannot convert non-const to const without const_cast 

आपने उसे अपने कैप्सूलीकरण किया गया है और केवल स्थिरांक गेटर और गैर स्थिरांक setters के साथ पहुँच सदस्यों, तो यह आपके लिए काफी अच्छा होना चाहिए। याद रखें कि लोग वास्तव में अपनी वस्तु को बदलना चाहते हैं, वे हमेशा const_cast कर सकते हैं। कॉन्स्ट-इफेक्शन केवल अनजाने गलतियों को पकड़ने के लिए है।

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