- C++

2010-02-18 9 views
5

ben gibi bir işlevi vardır, (. Referansla geçici dönen umurumda değil lütfen bu sorunu açıklamak için sadece bir örnektir)- C++

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

Bu açıkça derlenmeyecektir. Arayanların, foo'un T değiştirmeyeceğinden emin olmanın bir yolunu arıyorum. Bunu nasıl sağlayabilirim?

boost::shared_ptr için benzer davranışı gördüm. shared_ptr<T>, const shared_ptr<const T>'a dönüştürülebilir. Bunu nasıl yaptığını anlayamadım.

Herhangi bir yardım harika olurdu. Ben yanılmıyorsam

+0

Muhtemelen arayanların foo'nun * f * değerini değiştirmemesini sağlamaya çalışıyorsunuzdur. –

cevap

0

, boost::shared_ptr uygulama aralarında örtülü dönüşüm sağlayan const kaldırmak için RHS en tanıtıcısı üzerinde bir const_cast kullanır daha sonra bir argüman olarak bir const T& referansı alır ve açık olmayan yapıcı sahiptir. Böyle

şey:

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

aradığınız şey bu mu? Foo varsayarsak

+0

'const_cast' == Benim için kırmızı ringa balığı :) OP aslında bunun tersini yapan bir şey arıyor (ki bu daha doğal). –

1

böyle bir şey tanımlanır:

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; 
}; 

Sonra Foo müşterileri m_value değiştirmek olmadığını sağlamak amacıyla (bu ben arıyorum" ile kastedilen olduğunu varsayalım foo T ") değişmez arayanları sağlamak için şekilde, yani

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

nedenle, get_foo işlevi const Foo<T>& değil, bir dönmelidir, onun şablon parametresi yerine Foo nesnesi const kalifiye olabilmek için ihtiyaç const Foo<const T>&. foo sınıf tıpkı diğer dönüşüm olduğu gibi açıkça bu desteklemesi gerekir, böylece

#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

Bu harika bir yanıt olsa da, özellikle 'T' bir işaretçi türü veya foo bir "T *" depolarsa, özellikle 'ifadesinin gerekli olduğu durumlar olabilir. –

+0

@Tyler Agreed, OP bir şekilde belirsiz - Foo 'u Foo 'a dönüştürmeyi sorarken, aynı zamanda "arayanların foo'yu değiştirmeyeceğinden emin olmak için bir yol arıyorum", Benim cevabım Foo nesnesinin kendisinin kalifikasyonu ile elde etmeyi amaçlamaktadır. –

+0

Cevabınız için teşekkürler. @Tyler'in bahsettiği şeyi arıyorum. –

9

derleyici iki tamamen farklı ve ilgisiz türleri gibi foo<T> ve foo<const T> görür:

İşte tam, Derlenebilir örnek. foo sınıfı üzerinde denetiminiz varsa, bir kopya kurucusu veya bir örtük dönüştürme işleci (veya her ikisi de) sağlamanız gerekir.

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

Harika. Çok teşekkürler. –

0

Her şeyden önce, referans olarak yerel bir nesneyi döndürüyorsunuz ... bu iyi değil.

foo ve foo iki farklı türde olduğundan, bunları açıkça dönüştürmek için kod (dönüştürme yapıcıları) yazmanız gerekir.

, sen istediğini elde bunu dikkate için: const toplamamaddesi ve const olmayan belirleyiciler ile doğru bir şekilde kapsülleme yapılırsa

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 

ve tek erişim üyeleri, bu sizin için yeterince iyi olmalıdır. İnsanların gerçekten nesneyi değiştirmek isteyip istemediklerini hatırla, her zaman const_cast yapabilir. Const-doğruluk sadece kasıtsız hataları yakalamaktır.