1
\$\begingroup\$

Each node is a location within a layer. A Location may be a pointer or an index. A Layer is a container.

There are 4 types of node per Layer and Location types:

  • Node: Can change content of layer. Not a view of another node.
  • Const_node: Cannot change content of layer. Not a view of another node.
  • Node_view: Can change content of layer. A view of a Node.
  • Const_node_view: Cannot change content of layer. A view of a Const_node.

The code implements the types, their conversions, and traits.

Thanks for reviewing this.

Code:

#include <type_traits>
#include <vector>
#include <iostream>

// Node
template<typename Layer, typename Location=typename Layer::size_type>
class Node {
public:
    Node(Layer& lay, Location loc)
            : layer(layer), location(loc) {}

    auto content() { return layer[location]; }

    template<typename Other_layer, typename Other_location,
            typename=std::enable_if_t<
                    std::is_constructible<Layer, Other_layer>::value
                    && std::is_constructible<Location, Other_location>::value
            >
    >
    operator Node<Other_layer, Other_location>() {
        return Node<Other_layer, Other_location>(
                layer, location
        );
    };

    Node& operator=(const Node& n) { location = n.location; }

private:
    Layer& layer;
    Location location;
};

template<typename L, typename Loc=typename L::size_type>
using Node_view=Node<L, Loc&>;
template<typename L, typename Loc=typename L::size_type>
using Const_node=Node<const L, Loc>;
template<typename L, typename Loc=typename L::size_type>
using Const_node_view=Node<const L, Loc&>;

// Traits
template<template<typename...> class, typename...>
struct can_instantiate_to : public std::false_type {
};

template<template<typename...> class U, typename... T>
struct can_instantiate_to<U, U<T...>> : public std::true_type {
};

template<typename T>
struct is_node : std::integral_constant<
        bool, can_instantiate_to<Node, T>::value> {
};


template<typename T, typename=std::enable_if_t<is_node<T>::value>>
void foo(T node) {}

int main() {
    using V = std::vector<int>;
    V v(10u);
    // Node n1(v, 0);  // Error as Location type is deduced to be int.
    Node<V> n1(v, 0u);
    Node_view<V> n2(n1);
    Const_node<V> n3(n1);
    Const_node_view<V> n4(n1);

    foo(n1);
    foo(n2);
    foo(n3);
    foo(n4);

    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ is_constructible works but is_convertible doesn't. \$\endgroup\$ – R zu May 14 '18 at 2:49
  • \$\begingroup\$ Maybe that Location should just be a bool to show if the Node is a view or not. The Layer can provide the size_type. This will need to more things from <type_traits>, but it can avoid incorrect deduction of the Location type. The user also doesn't have to remember the correct Location type all of the time. \$\endgroup\$ – R zu May 14 '18 at 3:35
  • \$\begingroup\$ On the other hand, this means I have to make two node classes. One for pointer, another one for array... Pointer/array nodes are not convertible to each other. But I want the same algorithm to work on both kinds of nodes. \$\endgroup\$ – R zu May 14 '18 at 3:41
  • \$\begingroup\$ No need for two classes for array/pointer nodes. Just make the underlying container always return content of node by indexing operation. Maybe there is no need to check the Location type. Because int, int& are convertible in both direction anyway. \$\endgroup\$ – R zu May 14 '18 at 15:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.