3902. Return type of std::declval<cv void> should be (cv-unqualified) void

Section: 22.2.6 [declval] Status: New Submitter: Jiang An Opened: 2023-03-07 Last modified: 2023-03-22

Priority: 4

View other active issues in [declval].

View all other issues in [declval].

View all issues with New status.

Discussion:

Currently libc++ and libstdc++ determine the return type of std::declval like this:

template<class _Tp>
_Tp&& __declval_ret(int); // selected when _Tp is a referenceable type

template<class _Tp>
_Tp __declval_ret(long); // selected when _Tp is cv void

template<class _Tp>
decltype(__declval_ret<_Tp>(0)) declval() noexcept;

This strategy avoids instantiation of class templates. But it also drops cv-qualifiers of the return type when the type is cv void, which is different from the standard requirements. Such difference has no impact in normal use of std::declval, but is observable via decltype(std::declval<const void>) and its friends.

Given maintainers may think it's reasonable to keep the current implementation (see GCC Bugzilla #109049), it may be worthwhile to legitimate such strategy.

Should we make such construction ill-formed?

[2023-03-22; Reflector poll]

Set priority to 4 after reflector poll. "The testcase isn't even valid with the previous 'conforming' libstdc++ implementation." "declval isn't an addressable function, so would prefer if this was ill-formed rather than complicating the definition for this case."

Proposed resolution:

This wording is relative to N4928.

  1. Modify 22.2.1 [utility.syn], header <utility> synopsis, and 22.2.6 [declval] as indicated:

    template<class T>
      remove_cv_t<add_rvalue_reference_t<T>> declval() noexcept; // as unevaluated operand