Writing library-like code in C ++, I found that there is a special need for copy_cv_reference_t type copy_cv_reference_t :
struct A; struct B; static_assert(std::is_same< copy_cv_reference_t< A , B >, B >{}); static_assert(std::is_same< copy_cv_reference_t< A const , B >, B const >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A , B >, volatile B >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A const , B >, volatile B const >{}); static_assert(std::is_same< copy_cv_reference_t< A &, B >, B & >{}); static_assert(std::is_same< copy_cv_reference_t< A const &, B >, B const & >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A &, B >, volatile B & >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A const &, B >, volatile B const & >{}); static_assert(std::is_same< copy_cv_reference_t< A &&, B >, B && >{}); static_assert(std::is_same< copy_cv_reference_t< A const &&, B >, B const && >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A &&, B >, volatile B && >{}); static_assert(std::is_same< copy_cv_reference_t< volatile A const &&, B >, volatile B const && >{});
I came up with this for myself, using two approaches: using an identifier like determinants and only through SFINAE.
#include <type_traits> #if 1 enum class type_qual_id { value, const_value, lref, const_lref, rref, const_rref, volatile_value, volatile_const_value, volatile_lref, volatile_const_lref, volatile_rref, volatile_const_rref, }; template< type_qual_id tqid, typename type > struct add_type_qualifier; template< typename to > struct add_type_qualifier< type_qual_id::value , to > { using type = to ; }; template< typename to > struct add_type_qualifier< type_qual_id::const_value , to > { using type = to const ; }; template< typename to > struct add_type_qualifier< type_qual_id::lref , to > { using type = to & ; }; template< typename to > struct add_type_qualifier< type_qual_id::const_lref , to > { using type = to const & ; }; template< typename to > struct add_type_qualifier< type_qual_id::rref , to > { using type = to &&; }; template< typename to > struct add_type_qualifier< type_qual_id::const_rref , to > { using type = to const &&; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_value , to > { using type = volatile to ; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_const_value, to > { using type = volatile to const ; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_lref , to > { using type = volatile to & ; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_const_lref , to > { using type = volatile to const & ; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_rref , to > { using type = volatile to &&; }; template< typename to > struct add_type_qualifier< type_qual_id::volatile_const_rref , to > { using type = volatile to const &&; }; template< type_qual_id tqid, typename to > using add_qualifier_t = typename add_type_qualifier< tqid, to >::type; template< typename type > constexpr type_qual_id get_type_qualifier_id = type_qual_id::value ; template< typename type > constexpr type_qual_id get_type_qualifier_id< type const > = type_qual_id::const_value ; template< typename type > constexpr type_qual_id get_type_qualifier_id< type & > = type_qual_id::lref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< type const & > = type_qual_id::const_lref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< type && > = type_qual_id::rref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< type const && > = type_qual_id::const_rref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type > = type_qual_id::volatile_value ; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type const > = type_qual_id::volatile_const_value; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type & > = type_qual_id::volatile_lref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type const & > = type_qual_id::volatile_const_lref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type && > = type_qual_id::volatile_rref ; template< typename type > constexpr type_qual_id get_type_qualifier_id< volatile type const && > = type_qual_id::volatile_const_rref ; template< typename from, typename to > using copy_cv_reference_t = add_qualifier_t< get_type_qualifier_id< from >, to >; #else #include <type_traits> template< typename from, typename to > struct copy_cv { using type = to; }; template< typename from, typename to > struct copy_cv< from const, to > : copy_cv< from, to const > { }; template< typename from, typename to > struct copy_cv< volatile from, to > : copy_cv< from, volatile to > { }; template< typename from, typename to > struct copy_cv< volatile from const, to > : copy_cv< from, volatile to const > { }; template< typename from, typename to > struct copy_reference { using type = to; }; template< typename from, typename to > struct copy_reference< from &, to > : copy_reference< from, to & > { }; template< typename from, typename to > struct copy_reference< from &&, to > : copy_reference< from, to && > { }; template< typename from, typename to > using copy_cv_reference_t = typename copy_reference< from, typename copy_cv< std::remove_reference_t< from >, to >::type >::type; #endif
The first approach looks somewhat more artificial, but provides a "type qualifier identifier" as an additional side, and the latter may be useful in some situations. The second approach is inherently two-step. This may have disadvantages. In addition, it uses std::remove_reference_t to identify the cv-qualified type.
On the one hand, I know that the standard allows implementations to have traits of a "built-in" type . On the other hand, in the modern C ++ standard there is no typical feature.
What is the best implementation of copy_cv_reference_t type copy_cv_reference_t ? Not only between the two. Are there any better approaches to implement it? Is there a suggestion?
What about the names? What about the order of identifiers?