Reputation: 461
I have a custom vector type for math operations. I can give it a type directly
MyVector<2, int>vec{4,5};
or a reference_wrapper
int num1 = 4;
int num2 = 5;
MyVector<2, std::reference_wrapper<int>> vec2{std::ref(num1), std::ref(num2)};
which both works.
However, i'd like to restrict the MyVector
class to only take arithmetic types. Thought about putting a static_assert inside the class like this:
static_assert(std::is_arithmetic_v<T>, "Vector type T must be an arithmetic");
but of course this fails for reference_wrapper<int>
.
How can i "unwrap" an std::reference_wrapper to get the underlying type and use it in a type trait?
Upvotes: 1
Views: 430
Reputation: 218238
You might use std::conditional_t
and std::reference_wrapper<T>::type
:
// Helper
template <typename T> struct is_reference_wrapper : std::false_type{};
template <typename T> struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type{};
And then
static_assert(std::is_arithmetic_v<
typename std::conditional_t<
is_reference_wrapper<T>::value,
T,
std::type_identity<T>
>::type // Notice the extra type (in addition to _t)
>,
"Vector type T must be an arithmetic");
Note: Types provided in std::conditional
are "evaluated", so you can't do
std::conditional_t<is_reference_wrapper<T>::value,
typename T::type, // Hard error for types without `type` typename
T
>
so we delay that evaluation outside (both types should have ::type
, and C++20 std::type_identity
has one :) )
Upvotes: 0
Reputation: 24420
You might try:
template <typename T>
struct unwrap_ref
{
using type = T;
};
template <typename T>
struct unwrap_ref<std::reference_wrapper<T>>
{
using type = T;
};
template <typename T>
using unwrap_ref_type = typename unwrap_ref<T>::type;
And use static_assert(std::is_arythmetic_type_v<unwrap_ref_type<T>>);
Upvotes: 3