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

James Dennett james.dennett at gmail.com
Thu Aug 9 21:48:53 PDT 2012


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:
>> >>
>> >> On Wed, Aug 8, 2012 at 7:41 PM, Michael Price
>> >> <michael.b.price.dev at gmail.com> wrote:
>> >>>
>> >>> Given two objects, one and two that are references to some pure
>> >>> virtual
>> >>> type MyType, the following code compiles fine:
>> >>>
>> >>>     std::pair<std::reference_wrapper<MyType>,std::reference_wrapper<
>> >>> MyType >> mypair = std::make_pair(std::ref(one), std::ref(two));
>> >>>     std::swap(mypair.first, mypair.second);
>> >>>
>> >>> But if I replace the declaration of the pair object type with 'auto'
>> >>> as
>> >>> in:
>> >>>
>> >>>     auto mypair = std::make_pair(std::ref(one), std::ref(two));
>> >>
>> >>
>> >> mypair's type is std::pair<MyType&, MyType&>. See the make_pair
>> >> specification:
>> >>
>> >> template <class T1, class T2> pair<V1, V2> make_pair(T1&& x, T2&& y);
>> >>
>> >> Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y));
>> >> where V1 and V2 are determined as follows: Let Ui be decay<Ti>::type
>> >> for
>> >> each Ti. Then each Vi is
>> >> X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui.
>> >>
>> >
>> > So, I guess that std::pair<MyType&, MyType&> is assignable to
>> > std::pair<std::reference_wrapper<MyType&>,
>> > std::reference_wrapper<MyType&>>
>> > then?
>>
>> Given that reference_wrapper<T> is implicitly constructible from T&
>> (though not T&&), yes.
>>
>> >>
>> >> Then...
>> >>
>> >>>
>> >>> I get the following errors with std::swap:
>> >>>
>> >>> GameController.cpp:43:9: error: no matching function for call to
>> >>> 'swap'
>> >>>         std::swap(mypair.first, mypair.second);
>> >>>         ^~~~~~~~~
>> >>> /usr/include/c++/v1/type_traits:2902:5: note: candidate template
>> >>> ignored:
>> >>> disabled by 'enable_if' [with _Tp = MyType]
>> >>>     is_move_constructible<_Tp>::value &&
>> >>>     ^
>> >>
>> >>
>> >> 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.
>>
>> > 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).

-- James



More information about the cfe-dev mailing list