Created
February 6, 2016 23:26
-
-
Save lefticus/6fdccb18084a1a3410d5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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