Reputation: 51273
I how would I achieve the following for any derefernable type?
I find my current solution lacking since I need to do a class template specialization for every type I want it to work with:
template<typename T>
struct get_value_type
{
typedef typename T::value_type value_type;
};
template<typename E>
struct get_value_type<std::unique_ptr<E>>
{
typedef typename E::value_type value_type;
};
template<typename E>
struct get_value_type<std::shared_ptr<E>>
{
typedef typename E::value_type value_type;
};
template<typename E>
struct get_value_type<boost::optional<E>>
{
typedef typename E::value_type value_type;
};
I've tried the something along the ways of, which doesn't work.
template<typename T, typename IsIndirect = false_type>
get_value_type
{
typedef typename T::value_type value_type;
}
template<typename T>
struct get_value_type<T, true_type>
{
typedef decltype(*boost::declval<E>())::value_type value_type;
};
typedef get_value_type<T, is_indirect<T>::type> value_type;
Upvotes: 4
Views: 3709
Reputation: 219335
You're looking for std::pointer_traits<PointerType>::element_type
which lives in <memory>
.
#include <memory>
#include <boost/optional.hpp>
template <class Ptr>
struct MyPointer
{
};
template <class Ptr>
struct YourPointer
{
typedef signed char element_type;
};
int main()
{
static_assert
(
std::is_same
<
std::pointer_traits<std::unique_ptr<double>>::element_type,
double
>::value,
""
);
static_assert
(
std::is_same
<
std::pointer_traits<std::unique_ptr<short[]>>::element_type,
short
>::value,
""
);
static_assert
(
std::is_same
<
std::pointer_traits<std::shared_ptr<const char>>::element_type,
const char
>::value,
""
);
static_assert
(
std::is_same
<
std::pointer_traits<boost::optional<int*>>::element_type,
int*
>::value,
""
);
static_assert
(
std::is_same
<
std::pointer_traits<MyPointer<long long>>::element_type,
long long
>::value,
""
);
static_assert
(
std::is_same
<
std::pointer_traits<YourPointer<long long>>::element_type,
signed char
>::value,
""
);
}
20.6.3.1 Pointer traits member types [pointer.traits.types]
typedef
see belowelement_type
;Type:
Ptr::element_type
if such a type exists; otherwise,T
ifPtr
is a class template instantiation of the formSomePointer<T, Args>
, whereArgs
is zero or more type arguments; otherwise, the specialization is ill-formed.
Oh, and there's a specialization for pointer types as well:
template <class T>
struct pointer_traits<T*>
{
typedef T* pointer;
typedef T element_type;
typedef ptrdiff_t difference_type;
template <class U> using rebind = U*;
static pointer pointer_to(see below r) noexcept;
};
Upvotes: 7
Reputation: 477444
One solution which may be overly broad is to use a template template argument:
template <template <typename> class C, typename T>
struct get_value_type<C<T>>
{
typedef T value_type;
};
The more flexible solution would use variadics:
template <typename> struct get_first_param;
template <template <typename...> class C, typename T, typename ...Args>
struct get_first_param<C<T, Args...>>
{
typedef T value_type;
};
Upvotes: 2