[cfe-dev] Broken type deduction for pair of reference_wrappers?

James Dennett james.dennett at gmail.com
Thu Aug 9 23:28:44 PDT 2012


On Thu, Aug 9, 2012 at 10:35 PM, Michael Price
<michael.b.price.dev at gmail.com> wrote:
>
> On Thu, Aug 9, 2012 at 11:48 PM, James Dennett <james.dennett at gmail.com>
> wrote:
>>
>> On Thu, Aug 9, 2012 at 9:41 PM, Michael Price
>> <michael.b.price.dev at gmail.com> wrote:
>> > On Thu, Aug 9, 2012 at 10:02 PM, James Dennett <james.dennett at gmail.com>
>> > wrote:
>> >>
>> >> On Thu, Aug 9, 2012 at 7:16 PM, Michael Price
>> >> <michael.b.price.dev at gmail.com> wrote:
>> >> > On Thu, Aug 9, 2012 at 5:48 PM, Richard Smith <richard at metafoo.co.uk>
>> >> > wrote:
>>
> <SNIP>
>>
>> >> >>
>> >> >> your values can't be swapped, because MyType is not move
>> >> >> constructible,
>> >> >> because it's an abstract class type. The specification for 'swap'
>> >> >> says:
>> >> >>
>> >> >> Requires: Type T shall be MoveConstructible (Table 20) and
>> >> >> MoveAssignable
>> >> >> (Table 22).
>> >> >>
>> >> > Why does it compile (and it does in fact appear to execute correctly)
>> >> > if
>> >> > mypair is a pair of reference_wrappers then?
>> >>
>> >> Because reference_wrapper is CopyConstructible and CopyAssignable
>> >> (hence MoveConstructible and MoveAssignable), which is why it's a good
>> >> match for what std::pair needs.

In hindsight: The standard makes this claim, but I think it's wrong.

>> >> > I don't think that
>> >> > reference_wrapper is MoveConstrucible and MoveAssignable.
>> >>
>> >> Why not?
>> >
>> > The following web page mentions CopyConstructible and CopyAssignable,
>> > but
>> > not the move equivalents (granted, it is not authoritative).
>> > http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
>> >
>> > Why would copyable imply movable? You can definitely have types that are
>> > copyable but not movable as they can be deleted independently.
>>
>> The standard specifies the requirements for CopyConstructible and
>> CopyAssignable as refinements of  MoveConstructible and MoveAssignable
>> respectively (see tables 20-23).
>>
> 20.8.3 Class template reference_wrapper [refwrap]
>
> namespace std {
>   template <class T> class reference_wrapper {
>   public :
> ...
>     // construct/copy/destroy
>     reference_wrapper(T&) noexcept;
>     reference_wrapper(T&&) = delete; // do not bind to temporary objects
>     reference_wrapper(const reference_wrapper<T>& x) noexcept;
>     // assignment
>     reference_wrapper& operator=(const reference_wrapper<T>& x) noexcept;
> ...
>   };
> }
>
> Clearly that thing cannot be move constructed.  Maybe we are talking past
> each other at this point.  I feel that I still don't quite understand how a
> type could be considered MoveConstructible, yet have a deleted move
> constructor, but I'm willing to chalk that up to language-lawyer-ese.

You have a point, and I think that this is a defect in the standard.
reference_wrapper is documented as being
CopyConstructible/CopyAssignable, but it is not.  CopyConstructible
implies MoveConstructible which implies that construction from an
rvalue is permitted, but reference_wrapper disables that, so it's not
MoveConstructible and hence no longer meets the CopyConstructible
requirements (though its predecessor did in a world before move
semantics).

> Thanks for your help.  I guess it's back to specifying the full type instead
> of using the shiny 'auto' keyword.

Yes, if the special-casing of reference wrapper is getting in your way
then that's the way around it.

-- James



More information about the cfe-dev mailing list