Need to Know
Need to Know

Reputation: 31

Precedence between conversion operators in C++

During parameter resolution for a function which expects a pointer, why is the the reference-to-pointer conversion being selected rather than the pointer conversion?

template<typename T>
  class resource_ptr
  {
    public:
      operator T*()const {...} // <- C1: Convert to raw pointer for observation.
      operator T*&()     {...} // <- C2: Convert to reference to pointer, for assignment.
    ...
  };
...
void AcquireResource(resource_class *&);  // Assigns to the given pointer.
void UseResource(resource_class *);
...
resource_ptr<resource_class> rpResource;
AcquireResource(rpResource); // <- Calls C2, as expected.
UseResource(rpResource);     // <- Calls C2.  C1 would have been nice.

UseResource((resource_class*)rpResource); // <- Still calls C2. ???

Note that in this particular design, since C2 is granting write access, it asserts that the resource pointer is currently unassigned, to prevent resource leaks. So it's important that C2 only get used when we actually want the pointer by reference, as when passing to an API which assigns to it. As it stands, this design is broken.

(These conversions can be replaced with explicit functions, but I would like to understand this issue.)

Upvotes: 3

Views: 161

Answers (2)

ecatmur
ecatmur

Reputation: 157354

Your call to UseResource is an initialization of a non-class type (a pointer type), so the following clause applies:

8.5 Initializers [dcl.init]

15 [...] — Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3).

It doesn't matter whether you provide an explicit cast to the parameter type resource_class *; the cast changes the initialization from a copy-initialization to a direct-initialization, but (per 8.5:13) the distinction is irrelevant when the target type is a non-class type.

We then have two conversion functions with effective argument list (resource_ptr &) and (resource_ptr const &) (for the implicit object parameter) respectively; 13.3.3.2:3 applies for binding the references, so the less cv-qualified reference binding is preferred over the more cv-qualified binding.

Upvotes: 0

Bo Persson
Bo Persson

Reputation: 92261

The const version is used when the object to be converted is const. That works the same as with ordinary member functions.

I would go with named conversion functions, to make this easier to read.

Upvotes: 3

Related Questions