Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2008-06-26 10:13:03


On Jun 26, 2008, at 9:19 AM, David Abrahams wrote:

> Howard Hinnant <hinnant <at> twcny.rr.com> writes:
>
>> The tr1::is_convertible, which was born from boost::is_convertible,
>> considers its "from" to be an lvalue when detecting convertibility.
>> The C++0X std::is_convertible considers its "from" to be an rvalue
>> when detecting convertibility. If one wants to restrict
>> is_convertible to only consider lvalue froms, one simply specifies an
>> lvalue reference: is_convertible<F&, T>::value (from is now
>> considered as an lvalue).
>>
>> There is motivation for this change here:
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2255.html
>>
>> (search for "is_convertible").
>
> Very interesting! But now the question is, how do we resolve this
> (and other
> issues like it that will surely come up) for Boost?

I don't think there is any one answer. Sometimes namespaces are the
answer. boost::X need not be the same thing as std::tr1::X which need
not be the same thing as std::X.

In this particular case, I would expect a vanishingly small amount of
code to be broken by changing from the boost::is_convertible spec to
the std::is_convertible spec. If something is convertible from an
lvalue, then it is usually convertible from an rvalue. Obviously this
statement can be refuted with an example such as:

struct A
{
     A(B&);
};

But I am asserting that the above code is sufficiently rare,
especially when combined with the use of is_convertible.

For most uses of is_convertible, it does not matter whether the source
is considered an lvalue or an rvalue (pointers probably make up most
of the use cases). For those remaining cases where it does matter,
most of those want to consider the source an rvalue (move-only
types). And in a context where the "from" is a perfectly forwarded
template, [temp.deduct.call]/3 assures that is_convertible considers
the "from" with the same l/r-valueness as the argument being passed to
the deduced template:

struct B {};

struct A
{
    A(B&);
};

template <class T>
typename enable_if
<
    is_convertible<T, A>::value,
    void
>::type
foo(T&&);

void test()
{
    B b;
    foo(b); // ok, even with A(B&)
    foo(B()); // foo not found, A(B()) not allowed
}

-Howard


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