nshct
nshct

Reputation: 1230

Why does C++17's std::any not allow returning a movable value by any_cast?

While implementing C++17's std::any according to the specification available in this Wiki I stumbled across something that seemed nonsensical to me:

In the definition of the free function std::any_cast, which is used to retrieve values from an std::any instance, an overload for r-value references is supplied (It's the third one):

template< class ValueType >
ValueType any_cast(any&& operand); // (3)

Now, there is a requirement listed below the synopsis that applies to overloads 2 and 3 (that means also including the r-value overload):

2-3) Returns *any_cast<std::remove_reference_t<ValueType>>(&operand)

The definition does not seem to actually allow moving the data!

The function call is just redirected to the pointer-based overload; the information about the temporary nature of operand is lost!

Is it intended that I can't move out of an any instance? Is it just a error in the wiki? Am I wrong here?

Upvotes: 16

Views: 1421

Answers (2)

Marco A.
Marco A.

Reputation: 43662

The issue is in WP status at the time of writing this, which means:

WP - (Working Paper) - The proposed resolution has not been accepted as a Technical Corrigendum, but the full WG21/PL22.16 committee has voted to apply the Defect Report's Proposed Resolution to the working paper.

See the lwg here for more info: http://wg21.cmeerw.net/lwg/issue2509

A proposed resolution is indeed

For the third form, if is_move_constructible_v<ValueType> is true and is_lvalue_reference_v<ValueType> is false, std::move(*any_cast<remove_reference_t<ValueType>>(&operand)), otherwise, *any_cast<remove_reference_t<ValueType>>(&operand)

And the defect report list listing the WP: http://cplusplus.github.io/LWG/lwg-defects.html#2509

Upvotes: 11

milleniumbug
milleniumbug

Reputation: 15824

The implementation of std::any that doesn't require copying is perfectly possible to do. There's only one problem: what do you do when the user requests a copy of std::any? One solution to this problem is to make std::any move-only, the other is to make it throw an exception on copy constructor if the underlying type is move-only, yet another is to require being able to copy the underlying type. The third solution was chosen.

The requirements placed on ValueType being copy constructible are perfectly fine - since a type that's not copy constructible can't possibly be stored in the std::any instance, std::any_cast may as well make an always-failing cast a compiler error.

Now, the fact that the implementation of ValueType any_cast(any&& operand) doesn't allow moving seems to be an oversight - after all, a copy is a perfectly fine implementation of moving, and the implementation is free to delegate the job to the move constructor if it's there, and to copy constructor if not.

Upvotes: 0

Related Questions