C++でライブラリのようなコードを書くと、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 && >{});
私は、型修飾子の id を使用する方法と SFINAE のみを使用する方法の 2 つの方法を使用して、自分でそれを発明しました。
#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
最初のアプローチは少し人工的に見えますが、追加の側面として「型修飾子 ID」を提供し、後者は状況によっては便利です。2 番目のアプローチは、本質的に 2 段階のアプローチです。それには欠点があるかもしれません。さらにstd::remove_reference_t
、cv 修飾された型を明らかにする必要があります。
一方では、標準では実装が「組み込み」型の特性を持つことが許可されていることを知っています。一方、現在のC++標準には型特性はありません。
copy_cv_reference_t
型特性の最適な実装は何ですか? 上記の2つだけではありません。それを実装するためのより良いアプローチはありますか? 対応する提案はありますか?
ネーミングはどうする?IDの順番は?