Prev: return value optimization vs. returning a boost::shared_ptr of container
Next: Can const& functors be passed to functions efficiently (i.e. inlined, etc)?
From: Nick Hounsome on 14 Jun 2010 18:03 On 13 June, 11:09, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? Are you absolutely sure that you dont want const Foo<T>*? IMHO It is rarely useful to have Foo<const T> because Foo can always protect instance of T whether they are const or not - All you acheive is making the implementation harder. (Foo<const T*> MIGHT make sense). Compare your class Foo with std::vector - nobody uses vector<const int> but vector protects its content with overloads like reference operator[] ( size_type n ); const_reference operator[] ( size_type n ) const; It is generally logically wrong to be able to change anything OWNED by a const object hence it is not useful for an object to own const objects. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Mathias Gaunard on 14 Jun 2010 18:02 On Jun 13, 11:09 am, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? > > Assume that we have freedom to modify template Foo and it has not been > specialized... but can be specialized if necessary. For sake of > simplicity lets assume the following simplistic definition of Foo: > > template<class T> > struct Foo { > T* ptr; > bool flag; > ~Foo(){}; // This makes Foo ... not a POD type > > }; > template<class T> struct Foo { T* ptr; bool flag; ~Foo(){}; template<class U> Foo(const Foo<U>& u) : ptr(u.ptr), flag(u.flag) { } }; This allows to convert Foo<U> to Foo<T> is U is convertible to T. This is however not exactly what you want. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Chris Uzdavinis on 14 Jun 2010 18:16 On Jun 13, 5:09 am, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? > > Assume that we have freedom to modify template Foo and it has not been > specialized... but can be specialized if necessary. For sake of > simplicity lets assume the following simplistic definition of Foo: > > template<class T> > struct Foo { > T* ptr; > bool flag; > ~Foo(){}; // This makes Foo ... not a POD type > > }; > > I know reinterpret_cast would do it. But I am not sure if its the > safe. If Foo holds a pointer, and you want to convert Foo<T>* Foo<const T>*, then you're wanting to work with pointers to pointers? That's hard, as you can't change the semantics of raw pointers. However, if you treat Foo as a smart pointer you can use template members to achieve what you're asking, more or less. (That is, Foo<> is a proxy for the underlying pointer it holds-- in which case you *can* convert Foo<T> to Foo<const T>, but it is a copy of the object, not a reinterpreted meaning of the original. So while this code answers a different question than you asked, it is similar and may at least help you get an idea of other approaches (in general) to your problem. (Since, as earlier stated, when you want to do something that is directly prohibited by the language, you need to question your design.) template<class T> struct Foo { T* ptr; bool flag; Foo() : ptr(0), flag(false) { } template <class U> Foo(Foo<U> const & rhs) : ptr(rhs.ptr), flag(rhs.flag) { } template <class U> operator Foo<U> const () const { return Foo<U>(*this); } ~Foo() { /* do something */ } }; int main() { Foo<int> fi; Foo<const int> cfi; cfi = fi; // OK // fi = cfi; // Error } -- Chris [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: pfultz2 on 14 Jun 2010 18:34 On Jun 13, 6:09 am, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? > > Assume that we have freedom to modify template Foo and it has not been > specialized... but can be specialized if necessary. For sake of > simplicity lets assume the following simplistic definition of Foo: > > template<class T> > struct Foo { > T* ptr; > bool flag; > ~Foo(){}; // This makes Foo ... not a POD type > > }; > > I know reinterpret_cast would do it. But I am not sure if its the > safe. > > -Roshan { quoted clc++m banner removed; please do it yourself. -mod } You could do this by using inheritance, but this requires Foo<const T> to store the data since this is the base class. You could have it store a protected mutable data type, but only provide const only public methods, then in the derived class have the mutable methods. template<class T> class Foo : public Foo<const T> { public: //Mutatable methods //Notice we need to use "this" pointer because the base class is a templated T* get() { return this->data; } //Leave out the set method to avoid the T** -> T const** problem }; template<class T> class Foo<const T> { protected: T * data; public: //Const methods const T* get() const { return data; } }; This is an idea and depends on what you are trying to accomplish. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 14 Jun 2010 23:12
On Jun 15, 10:03 am, Nick Hounsome <nick.houns...(a)gmail.com> wrote: > On 13 June, 11:09, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: This has been debated here before. Perhaps I have a more coherent argument this time. > > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? > > Are you absolutely sure that you dont want const Foo<T>*? Yes... > IMHO It is rarely useful to have Foo<const T> because Foo can always > protect instance of T whether they are const or not - All you acheive > is making the implementation harder. (Foo<const T*> MIGHT make sense). Unfortunately, you are mistaken. Consider: template<class C> class Foo { private: C* ptr; public: Foo(C* p) :ptr(p); C* get(){ return ptr; } const C* get() const { return ptr; } }; Now consider you have a function like this: void func(const Foo<int>& f) { Foo<int> not_const_anymore(f); *not_const_anymore.get() = 0; } Because you can copy construct a non-const object from a const one, you can with some effort circumvent the access controls. > Compare your class Foo with std::vector - nobody uses vector<const > int> but vector protects its content with overloads like > reference operator[] ( size_type n ); > const_reference operator[] ( size_type n ) const; I agree 100%. When a class has value semantics (e.g. vector<int>) a const class behaves as if the values it points to are const. That is nice since a const vector works as a const array. However, if you have an object with reference semantics, it is impossible so make a const object behave as if it points to const data properly. The problem is that const behaves very subtly differently for pointers than for classes. This is well illustrated by the fact that it is impossible to get pointer like semantics with classes. Many people (myself included) understand the precise reasons behind how this difference manifests, but nevertheless disagree. The reason is that const A* is just a const version of A*, so the conversion can happen freely. In this case, the object IS NOT constant. However, const A is a version of A, but the object IS constant. This is a semantic difference. At this point people usually argue that of course it is the case because the const binds to whatever the * points to in a declaration. I do not disagree since that is manifestly the case. However it is still a semantic difference. Auto-consting of pointers is very different from auto-consting of objects. It is still impossible to write a class that has pointer like reference semantics. Because const has a special place in C++ with respect to automatic conversions, this actually really is a semantic difference. Conversions to const happen automatically even in the presence of templates. Other conversions do not. In order to write a class with pointer like semantics, one needs extra syntactic overhead. Syntactic overhead is bad. If you are still unconvinced, let me illustrate it with an example: Foo is a type which allows slicing. I've omitted the actual slicing part. Assume it happens. template<class C> struct Foo { const Foo<C> nonconst_slice() { return Foo(); } const Foo<const C> const_slice() { return Foo<const C>(); } }; template<class C> struct Foo<const C> { Foo(); Foo(const Foo<C>&); //Allow automatic conversion to Foo<const C>; }; void do_something_int(const Foo<const int>& f); template<class C> void do_something(const Foo<const C>& f); int main() { Foo<int> f; do_something_int(f); do_something_int(f.nonconst_slice()); do_something_int(f.const_slice()); do_something(f); //Error: no automatic conversion. Syntactic overhead required do_something(f.nonconst_slice()); //Error: no automatic conversion: Syntactic overhead required do_something(f.const_slice()); } See? Classes with pointer/reference semantics simply do not behave as nicely as pointers. > It is generally logically wrong to be able to change anything OWNED by > a const object hence it is not useful for an object to own const > objects. I largely agree. C++ makes the unusual case the default and the obvious case impossible to implement. -Ed -- (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258) /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1 r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12 d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |