This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2769. Redundant `const` in the return type of `any_cast(const any&)`

Section: 20.8.5 [any.nonmembers] Status: C++17 Submitter: Casey Carter Opened: 2016-09-02 Last modified: 2017-07-30

Priority: 0

View other active issues in [any.nonmembers].

View all other issues in [any.nonmembers].

View all issues with C++17 status.

Discussion:

The overload of `any_cast` that accepts a reference to constant `any`:

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

is specified to return `*any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand)` in [any.nonmembers]/5. This calls the pointer-to-constant overload of `any_cast`:

>     template<class ValueType>
>       const ValueType* any_cast(const any* operand) noexcept;

which is specified as:

> Returns: If `operand != nullptr && operand->type() == typeid(ValueType)`, a pointer to the object contained by `operand`; otherwise, `nullptr`.

Since `typeid(T) == typeid(const T)` for all types `T`, `any_cast<add_const_t<T>>(&operand)` is equivalent to `any_cast<T>(&operand)` for all types `T` when operand is a constant lvalue `any`. The `add_const_t` in the return specification of the first overload above is therefore redundant.

[2016-09-09 Issues Resolution Telecon]

P0; move to Tentatively Ready

Casey will provide combined wording for this and 2768, since they modify the same paragraph.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 1. Modify 20.8.5 [any.nonmembers] as indicated:

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

>    > -4- Requires: `is_reference_v<ValueType>` is `true` or `is_copy_constructible_v<ValueType>` is `true`. Otherwise the program is ill-formed.

>    > -5- Returns: For the first form, `*any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand)`. For the second and third forms, `*any_cast<remove_reference_t<ValueType>>(&operand)`.

>    > […]

[2016-09-09 Casey improves wording as determined by telecon]

The presented resolution is intended as the common wording for both LWG 2768 and LWG 2769.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 1. Modify 20.8.5 [any.nonmembers] as indicated:

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

>    > -4- Requires: `is_reference_v<ValueType>` is `true` or `is_copy_constructible_v<ValueType>` is `true`. Otherwise the program is ill-formed.

>    > -5- Returns: For the first form, `*any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand)`. For the and second and third forms, `*any_cast<remove_reference_t<ValueType>>(&operand)`. For the third form, `std::forward<ValueType>(*any_cast<remove_reference_t<ValueType>>(&operand))`.

>    > […]

[2016-10-05, Tomasz and Casey reopen and improve the wording]

The constraints placed on the non-pointer `any_cast` overloads are neither necessary nor sufficient to guarantee that the specified effects are well-formed. The current PR for LWG 2769 also makes it possible to retrieve a dangling lvalue reference to a temporary any with e.g. `any_cast<int&>(any{42})`, which should be forbidden.

[2016-10-16, Eric made some corrections to the wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 1. Modify 20.8.5 [any.nonmembers] as indicated:

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

>    > -4- Requires: `is_reference_v<ValueType>` is `true` or `is_copy_constructible_v<ValueType>` is `true`.For the first overload, `is_constructible_v<ValueType, const remove_cv_t<remove_reference_t<ValueType>>&>` is `true`. For the second overload, `is_constructible_v<ValueType, remove_cv_t<remove_reference_t<ValueType>>&>` is `true`. For the third overload, `is_constructible_v<ValueType, remove_cv_t<remove_reference_t<ValueType>>>` is `true`. Otherwise the program is ill-formed.

>    > -5- Returns: For the first form, `*any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand)`. For the second and third forms, `*any_cast<remove_reference_t<ValueType>>(&operand)`.For the first and second overload, `static_cast<ValueType>(*any_cast<remove_cv_t<remove_reference_t<ValueType>>>(&operand))`. For the third overload, `static_cast<ValueType>(std::move(*any_cast<remove_cv_t<remove_reference_t<ValueType>>>(&operand)))`.

>    > […]

[2016-11-10, LWG asks for simplification of the wording]

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

1. Modify 20.8.5 [any.nonmembers] as indicated:

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

   > -?- Let `U` be the type `remove_cv_t<remove_reference_t<ValueType>>`.

   > -4- Requires: `is_reference_v<ValueType>` is `true` or `is_copy_constructible_v<ValueType>` is `true`.For the first overload, `is_constructible_v<ValueType, const U&>` is `true`. For the second overload, `is_constructible_v<ValueType, U&>` is `true`. For the third overload, `is_constructible_v<ValueType, U>` is `true`. Otherwise the program is ill-formed.

   > -5- Returns: For the first form, `*any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand)`. For the second and third forms, `*any_cast<remove_reference_t<ValueType>>(&operand)`.For the first and second overload, `static_cast<ValueType>(*any_cast<U>(&operand))`. For the third overload, `static_cast<ValueType>(std::move(*any_cast<U>(&operand)))`.

   > […]