Skip to content

Instantly share code, notes, and snippets.

@lefticus
Created February 6, 2016 23:26
Show Gist options
  • Save lefticus/6fdccb18084a1a3410d5 to your computer and use it in GitHub Desktop.
Save lefticus/6fdccb18084a1a3410d5 to your computer and use it in GitHub Desktop.

Revisions

  1. lefticus created this gist Feb 6, 2016.
    122 changes: 122 additions & 0 deletions value_of.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    #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);

    }