Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-03-05 15:44:27


Rani,

Here's what Steve Adamczyk (Mr. overload resolution) at EDG had to say
about it:

I tracked down why we do what we do. It comes down to 13.3.3.1.2/4:

4 A conversion of an expression of class type to the same class type is
  given Exact Match rank, and a conversion of an expression of class
  type to a base class of that type is given Conversion rank, in spite
  of the fact that a copy constructor (i.e., a user-defined conversion
  function) is called for those cases.

Now, the idea of using the auto_ptr kind of trick (copying by
way of an auxiliary class) was not thought of when this paragraph
was done, but the point was that for purposes of overload
resolution copying X to X is always an exact match even if
something is called to do the copy.

Now, we could do a core issue to find out what this paragraph means
for the auto_ptr kind of case. I have to say, though, that
it would be an expensive thing to have to check everywhere that a
copy that looks like an exact match is done, and there's nothing
that says that calling a conversion function and copy constructor
is less efficient than calling a copy constructor, so I'd be
inclined to say that it should just be clarified to say that
such a copy is considered an exact match regardless of the
actual mechanism used to perform the copy.

Steve

----- Rani wrote this ----

Interesting challenge (at least for me).
In first glance it seems to be impossible which made it even more
interesting.

typedef char (&yes)[1];
typedef char (&no) [2];

//
// TODO: handle types that can't be members
// (e.g. void, abstract, functions)
//
template<class T>
struct has_regular_ctor
{
private:
    struct ctor_tester
    {
        T t;
        struct B {};
        operator B() const;
        ctor_tester(B);
    private:
        // VC warnings
        ctor_tester& operator=(ctor_tester const&);
    };

    static yes check(ctor_tester, int);
    template<typename U>
    static no check(ctor_tester const&, U);

    static ctor_tester const& get();

public:
    static const bool value =
        sizeof(check(get(), 0)) == sizeof(yes);
};

struct A1 { A1(A1&); };
struct A2 { A2(A2 const&); };

typedef char test[!has_regular_ctor<A1>::value];
typedef char test[!has_regular_ctor<A1 const>::value];
typedef char test[ has_regular_ctor<A2>::value];
typedef char test[ has_regular_ctor<A2 const>::value];
typedef char test[ has_regular_ctor<int>::value];

The above code compiled fine with VC7.1 beta but failed to compile using EDG
and GCC.
Here is an explanation for why I think that it's compliant:

The form of the ctor of ctor_tester is the same as its member t (12.8/5). In
case the ctor argument has const qualifier then both check functions has an
exact match (13.3.3.1.1/3), the first check using Lvalue-transformation and
the second using identity. The ambiguity buster in this case is the
non-template function.
In case that the ctor is not const then the first version is viable using
user defined conversion sequence (like auto_ptr: ctor_tester -> B) and the
second is still identity.

Overloading is so complex that I have doubts and I'll be happy to ear a
second opinion.

Rani

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk