3446. indirectly_readable_traits ambiguity for types with both value_type and element_type

Section: 24.3.2.2 [readable.traits] Status: C++23 Submitter: Casey Carter Opened: 2020-05-15 Last modified: 2023-11-22

Priority: 2

View all other issues in [readable.traits].

View all issues with C++23 status.

Discussion:

Per 24.3.2.2 [readable.traits], indirectly_readable_traits<T>::value_type is the same type as remove_cv_t<T::value_type> if it denotes an object type, or remove_cv_t<T::element_type> if it denotes an object type. If both T::value_type and T::element_type denote types, indirectly_readable_traits<T>::value_type is ill-formed. This was perhaps not the best design, given that there are iterators in the wild (Boost's unordered containers) that define both nested types. indirectly_readable_traits should tolerate iterators that define both nested types consistently.

[2020-07-17; Priority set to 2 in telecon]

Previous resolution [SUPERSEDED]:

This wording is relative to N4861.

  1. Modify 24.3.2.2 [readable.traits] as indicated:

    […]
    template<class> struct cond-value-type { }; // exposition only
    
    template<class T>
      requires is_object_v<T>
    struct cond-value-type<T> {
      using value_type = remove_cv_t<T>;
    };
    
    template<class> struct indirectly_readable_traits { };
    
    […]
    
    template<class T>
      requires requires { typename T::value_type; }
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::value_type> { };
    
    template<class T>
      requires requires { typename T::element_type; }
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::element_type> { };
    
    template<class T>
      requires requires {
        typename T::element_type;
        typename T::value_type;
        requires same_as<
          remove_cv_t<typename T::element_type>,
          remove_cv_t<typename T::value_type>>;
      }
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::value_type> { };
    
    […]
    

[2020-07-23; Casey improves wording per reflector discussion]

[2020-08-21; moved to Tentatively Ready after five votes in favour in reflector poll]

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

  1. Modify 24.3.2.2 [readable.traits] as indicated:

    […]
    template<class> struct cond-value-type { }; // exposition only
    
    template<class T>
      requires is_object_v<T>
    struct cond-value-type<T> {
      using value_type = remove_cv_t<T>;
    };
    
    template<class T>
    concept has-member-value-type = requires { typename T::value_type; }; // exposition only
    
    template<class T>
    concept has-member-element-type = requires { typename T::element_type; }; // exposition only
    
    template<class> struct indirectly_readable_traits { };
    
    […]
    
    template<classhas-member-value-type T>
      requires requires { typename T::value_type; }
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::value_type> { };
    
    template<classhas-member-element-type T>
      requires requires { typename T::element_type; }
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::element_type> { };
    
    template<classhas-member-value-type T>
      requires has-member-element-type<T> &&
               same_as<remove_cv_t<typename T::element_type>, remove_cv_t<typename T::value_type>>
    struct indirectly_readable_traits<T>
      : cond-value-type<typename T::value_type> { };
    
    […]