c++type-conversion

Return types can be cv-qualified only if it is a class type?


From the below program I learned, that if I declare a function with a cv-qualified return type,

Why is the language inconsistent in this regard?

#include <type_traits>

template <auto>
struct ReturnTypeT;

template <class Ret, class... Pars, Ret (*FPtr)(Pars...)>
struct ReturnTypeT<FPtr> : std::type_identity<Ret> {};

template <auto FPtr>
using ReturnType = ReturnTypeT<FPtr>::type;


enum MyEnum {};
class MyClass {};

template <class T>
T returnT();

#define ASSERT_SAME(T1, T2)   static_assert(std::is_same_v<T1, T2>)

ASSERT_SAME(ReturnType< returnT<const    int>     >, const    int);
ASSERT_SAME(ReturnType< returnT<const    MyEnum>  >, const    MyEnum);
ASSERT_SAME(ReturnType< returnT<const    MyClass> >, const    MyClass);
ASSERT_SAME(ReturnType< returnT<volatile int>     >, volatile int);
ASSERT_SAME(ReturnType< returnT<volatile MyEnum>  >, volatile MyEnum);
ASSERT_SAME(ReturnType< returnT<volatile MyClass> >, volatile MyClass);

ASSERT_SAME(decltype( returnT<const    int>()     ), /*?*/    int);
ASSERT_SAME(decltype( returnT<const    MyEnum>()  ), /*?*/    MyEnum);
ASSERT_SAME(decltype( returnT<const    MyClass>() ), const    MyClass);
ASSERT_SAME(decltype( returnT<volatile int>()     ), /*????*/ int);
ASSERT_SAME(decltype( returnT<volatile MyEnum>()  ), /*????*/ MyEnum);
ASSERT_SAME(decltype( returnT<volatile MyClass>() ), volatile MyClass);

Online demo. Note, that returning with volatile types is deprecated since C++20, see here.


Solution

  • This is specified in [expr.type]#2.

    If a prvalue initially has the type "cv T", where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.

    Source: C++23, C++ latest draft.