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: Ulrich Eckhardt on 16 Jun 2010 22:34 Edward Rosten wrote: > On Jun 15, 9:02 pm, Nick Hounsome <nick.houns...(a)gmail.com> wrote: >> It [copying and assignment] can be prevented with: >> >> Foo(const Foo<T>&) = delete; // or private unimplemented >> Foo& operator=(const Foo<T>&) = delete; // or provate unimplemented > > ..and that prevents one returning a Foo from a free function. Take a look at std::auto_ptr and how it does this. Basically, you can implement move semantics while still disallowing copying. >> It is straightforward to provide a conversion from Foo<T> to Foo<const >> T> >> if that is what you need. > > No, it is not! You can define a conversion, but it will not get used > automatically. Try compiling the code I posted: it has the conversion > defined. It does not compile, because C++ won't do arbitrary searches > through instantiating templates to find something that will match. You > have to add extra syntactic overhead. In this case, you can turn it around and create a template constructor instead, which will be considered. > My basic point is this: the automatic addition of const to raw > pointers is perfect for implementing reference semantics. There is no > way of replicating this with classes, without introducing a lot of > needless syntactic overhead. This is IMO a flaw, because it means that > built-in types (and worse, raw pointers) behave better than user- > defined ones. Take a look at boost::shared_ptr. Those behave just like raw pointers, i.e. a shared_ptr<Foo> will be implicitly converted to a shared_ptr<Foo const> if need is. However, just like with raw pointers, you can not pass the address of a shared_ptr<Foo> to a function taking the address of a shared_ptr<Foo const>, the reason being that it would allow you to circumvent cv-qualifications, as has been mentioned in this thread. Uli -- Sator Laser GmbH Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 18 Jun 2010 00:31 On Jun 17, 2:34 pm, Ulrich Eckhardt <eckha...(a)satorlaser.com> wrote: > Take a look at boost::shared_ptr. Those behave just like raw pointers, i.e. > a shared_ptr<Foo> will be implicitly converted to a shared_ptr<Foo const> You are mistaken. The conversion to a const version of the same type is different from conversions to other types. By way of illustration, this code snippet does not compile: #include <tr1/memory> using namespace std::tr1; template<class C> void func1(const shared_ptr<C const>&); template<class C> void func2(const C*); int main() { shared_ptr<int> i1; int* i2; func1(i1); //Not OK func2(i2); //OK -- and does the right thing. func1(shared_ptr<const int>(i1)); //Yuck! } If func simply accepted a const C* instead, then it would compile just fine. One can make it compile, but the syntactic overhead is just plain nasty. -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! ]
From: Mathias Gaunard on 18 Jun 2010 04:09 On 18 juin, 16:31, Edward Rosten <edward.ros...(a)gmail.com> wrote: > template<class C> void func1(const shared_ptr<C const>&); > template<class C> void func2(const C*); > > int main() > { > shared_ptr<int> i1; > int* i2; > > func1(i1); //Not OK It's not that it's not OK to do this, it's that implicit conversions aren't taken into account in template deduction contexts. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 18 Jun 2010 10:28 On 18 Jun., 17:31, Edward Rosten <edward.ros...(a)gmail.com> wrote: > On Jun 17, 2:34 pm, Ulrich Eckhardt <eckha...(a)satorlaser.com> wrote: > > > Take a look at boost::shared_ptr. Those behave just like raw pointers, i.e. > > a shared_ptr<Foo> will be implicitly converted to a shared_ptr<Foo const> > > You are mistaken. The conversion to a const version of the same type > is different from conversions to other types. By way of illustration, > this code snippet does not compile: > > #include <tr1/memory> > using namespace std::tr1; > > template<class C> void func1(const shared_ptr<C const>&); > template<class C> void func2(const C*); > > int main() > { > shared_ptr<int> i1; > int* i2; > > func1(i1); //Not OK > func2(i2); //OK -- and does the right thing. > func1(shared_ptr<const int>(i1)); //Yuck! > > } > > If func simply accepted a const C* instead, then it would compile just > fine. One can make it compile, but the syntactic overhead is just > plain nasty. I don't think that the current state is a inherent defect in C++ templates. As usual, if you want to realize a special T -> U relation, you need to implement that, e.g. you could use inheritance to simulate the same effect: template<class T> struct shared_ptr; template<class T> struct shared_ptr<const T> { ... // }; template<class T> struct shared_ptr : shared_ptr<const T> { ... // }; This way you program above will be well-formed and it will also accept the following conversions: shared_ptr<int>* pi2 = 0; shared_ptr<const int>* cpi2 = pi2; shared_ptr<int> i1; shared_ptr<const int> ci1 = i1; Above is just a sketch, here are some details for a possible implementation which ensures that the member data is hold only once: template<class T> class shared_ptr; template<class T> class shared_ptr<const T> { friend class shared_ptr<T>; T* ptr; public: shared_ptr(const T* ptr = 0) : ptr(const_cast<T*>(ptr)) {} const T* get() const { return this->ptr; } // ... }; template<class T> class shared_ptr : public shared_ptr<const T> { public: shared_ptr(T* p = 0) : shared_ptr<const T>(p) {} T* get() const { return this->ptr; } // ... }; Maybe there are other ways to realize the same effect - I never had the need for such a relation. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 21 Jun 2010 08:37
On Jun 18, 8:09 pm, Mathias Gaunard <loufo...(a)gmail.com> wrote: > On 18 juin, 16:31, Edward Rosten <edward.ros...(a)gmail.com> wrote: > > > template<class C> void func1(const shared_ptr<C const>&); > > template<class C> void func2(const C*); > > > int main() > > { > > shared_ptr<int> i1; > > int* i2; > > > func1(i1); //Not OK > > It's not that it's not OK to do this, it's that implicit conversions > aren't taken into account in template deduction contexts. ....making it entirely not OK. That's one of the points I've been trying to make. Once one tries to get pointer-like semantics with templated functions, a nasty syntactic overhead is introduced. -- (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! ] |