From: Ulrich Eckhardt on
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
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
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
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
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! ]