Skip to content

Instantly share code, notes, and snippets.

@MORTAL2000
Forked from lefticus/value_of.cpp
Created January 14, 2017 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MORTAL2000/2304d92b56919ab9444dbfb78ca8a620 to your computer and use it in GitHub Desktop.
Save MORTAL2000/2304d92b56919ab9444dbfb78ca8a620 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
#include <type_traits>
template< class ... > using void_t = void;
template< class T , class = void >
struct is_dereferenceable : std::false_type
{ };
template< class T >
struct is_dereferenceable<T, void_t<decltype( &std::remove_reference_t<T>::operator* )>> : std::true_type
{
typedef std::result_of_t<decltype(&std::remove_reference_t<T>::operator*)(T)> result;
};
template< class T >
struct is_dereferenceable<T,
std::enable_if_t<
!std::is_void<std::remove_pointer_t<T>>::value
&& std::is_pointer<std::remove_reference_t<T>>::value
>
> : std::true_type
{
typedef std::add_lvalue_reference_t<std::remove_pointer_t<std::remove_reference_t<T>>> result;
};
template< class T >
constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
template< class T , class = void >
struct has_arrow_operator : std::false_type
{ };
template< class T >
struct has_arrow_operator<T, void_t<decltype( &std::decay_t<T>::operator-> )>> : std::true_type
{
typedef typename std::result_of_t<decltype(&std::decay_t<T>::operator->)(T)> result;
};
template< class T >
struct has_arrow_operator<T, std::enable_if_t<std::is_pointer<std::remove_reference_t<T>>::value>> : std::true_type
{
typedef std::remove_reference_t<T> result;
};
template< class T >
constexpr bool has_arrow_operator_v = has_arrow_operator<T>::value;
template< class T , class = void >
struct is_model_of_pointer : std::false_type
{ };
template< class T >
struct is_model_of_pointer<T,
std::enable_if_t<
is_dereferenceable<T>()
&& has_arrow_operator<T>()
&& std::is_same<
std::remove_pointer_t<typename has_arrow_operator<T>::result>,
std::remove_reference_t<typename is_dereferenceable<T>::result>
>::value
>
> : std::true_type
{ };
template< class T >
constexpr bool is_model_of_pointer_v = is_model_of_pointer<T>::value;
template<typename V>
auto value_of(V &&v) -> std::enable_if_t<is_model_of_pointer_v<V>, decltype(*v)> {
return *v;
}
template<typename V>
auto value_of(V &&v) -> std::enable_if_t<!is_model_of_pointer<V>::value, V> {
return std::forward<V>(v);
}
int main() {
static_assert(is_dereferenceable<std::vector<int>::iterator>(), "iter");
static_assert(is_dereferenceable<std::vector<int>::const_iterator>(), "const_iter");
static_assert(is_dereferenceable<int*>(), "ptr");
static_assert(!is_dereferenceable<int>(), "value");
static_assert(is_dereferenceable<std::shared_ptr<int>>(), "shared_ptr");
static_assert(is_dereferenceable<std::unique_ptr<int>>(), "unique_ptr");
static_assert(!is_dereferenceable<void *>(), "void *");
static_assert(!is_dereferenceable<const void *>(), "const void *");
const std::array<int, 3> a{1,2,3};
const std::vector<int> v1{4,5,6};
const std::vector<std::shared_ptr<int>> v2{std::make_shared<int>(7),std::make_shared<int>(8),std::make_shared<int>(9)};
const std::vector<int *> v3{new int(10), new int(11), new int(12)};
const std::vector<std::unique_ptr<int>> v4 =
[](){
std::vector<std::unique_ptr<int>> v;
v.emplace_back(std::make_unique<int>(13));
v.emplace_back(std::make_unique<int>(14));
v.emplace_back(std::make_unique<int>(15));
return v;
}();
const std::vector<std::vector<int>::const_iterator> v5{v1.begin()+2, v1.begin()+1, v1.begin()};
const auto printer = [](const auto &v){ std::cout << value_of(v) << '\n'; };
const auto print_all = [printer](const auto &c) { std::for_each(std::begin(c), std::end(c), printer); };
print_all(a);
print_all(v1);
print_all(v2);
print_all(v3);
print_all(v4);
print_all(v5);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment