Type System for Layers and Nodes

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












Overview



The following is a type system of layers (A, B, C, Null) and nodes for a library.



A version that prints colored text for debugging is on github.



Thanks in advance for reviewing this.




Features



The user can create a stack of layers:



  • The type of a stack can be C<B<A<>>>, B<C<A<>>>, B<A> or C<A>

  • The lowest layer of a stack must be a memory layer (e.g. A in code).

Conversions between nodes produced by any layers of a stack is possible.




  • For examaple, consider a stack C<B<A<>>>:



    • The 3 layers of the stack would create 3 kinds of nodes, called Na, Nb, Nc.


    • Na, Nb, Nc can convert to each other.

    • The conversion should happen stepwise. For example, conversionNa->Nc involves conversions Na->Nb->Nc


    • Na, Nb, Nc are respectively instantiation of class templates Node_a, Node_b, Node_c


    • layer_type::node_type are Na, Nb, Nc for the 3 layers.


Can write functions that only accept instantiation of a node template. This is enabled by std::enable_if_t and traits in the library.




  • is_node<T> checks if type T is a node.


  • converted_node_is_instantiation_of<T, Node_template> checks if some conversion of T is an instantiation of the Node_template.


  • can_instantiate_to<template, T> checks if T is an instantiaion of the template.


Use case



  • Library of stackable layers with proxies for manipulating the layers.


Problem



  • The is_node trait is not quite extensible.


  • Constraining multiple arguments of a function to accept only instantiation of some node_templates is tedious. Example for constraining just one argument:



template<typename T,
typename=std::enable_if_t<
node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)
// convert c to an actual instantiation of Node_c ...




  • A possible alternative is a helper that checks with static_assert. This helper would also handle type conversion of nodes. But that has other problems as well:


// Possible api
void foo(const T& c)
auto c2 = convert_node<Node_c>(c);


// void foo(const T& b) // can't overload this way.
// auto b2 = convert_node<Node_b>(b);
//



  • The compilation error message for conversions between node types is not very clear. Whether a conversion between nodes is possible actually depends on the stack of layers. But the stack of layers is not shown in the error message.


  • Colored error message in run time won't help if the program doesn't compile.


  • No specification for node, const_node, view_of_node, and view_of_const_node.


type_system.cpp



#include <iostream>
#include <type_traits>

// -- [[ Forward declarations ]] -- //
template<class> struct Node_a;
template<class> struct Node_b;
template<class> struct Node_c;
struct Node_null;

template<class, class, int> struct B;
template<class, class> struct C;
struct Null;

// -- [[ Node converters ]] -- //
template<class Self, class Next>
struct Chained_converter
template<class Destination,
class = std::enable_if_t<
std::is_constructible_v<Destination, Next>
&& !std::is_same<Destination, Null>::value
>
>
operator Destination()
return static_cast<Self*>(this)->operator Next();

;

template<class L>
struct Node_converter
: Chained_converter<class L::node_type,
class L::prev_type::node_type>,
Chained_converter<class L::node_type,
class L::next_type::node_type>
;

template<typename Node> using Promote_node = typename
Node::layer_type::next_type::node_type;

template<typename Node> using Demote_node = typename
Node::layer_type::prev_type::node_type;


// -- [[ Node ]] -- //
struct Node_null
using layer_type=Null;
;

template <class Self, class L>
class Node_base : public Node_converter<L>
using next_type = typename L::next_type::node_type;
using prev_type = typename L::prev_type::node_type;
public:
operator prev_type() return prev_type();
operator next_type() return next_type();
;

template<class L>
struct Node_a : public Node_base<Node_a<L>, L>
using layer_type = L;
using Node_base<Node_a<L>, L>::Node_base;
;

template<class L>
struct Node_b : public Node_base<Node_b<L>, L>
using layer_type = L;
using Node_base<Node_b<L>, L>::Node_base;
;

template<class L>
struct Node_c : public Node_base<Node_c<L>, L>
using layer_type = L;
using Node_base<Node_c<L>, L>::Node_base;
;

// -- [[ Layers ]] --
struct Null
using node_type = Node_null;
;

template<class Raw_prev=Null, class Next=Null>
struct A
using self_type = A<Raw_prev, Next>;
using node_type = Node_a<self_type>;
using prev_type = Null;
using next_type = Next;
template<class New_next>
using rebase = A<Raw_prev, New_next>;
;

template<class Raw_prev, class Next=Null, int Parm = 1>
struct B
using self_type = B<Raw_prev, Next, Parm>;
using node_type = Node_b<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next>
using rebase = B<Raw_prev, New_next, Parm>;
;

template<class Raw_prev, class Next=Null>
struct C
using self_type = C<Raw_prev, Next>;
using node_type = Node_c<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next> using rebase = C<Raw_prev, New_next>;
;

// -- [[ Node 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 L>
struct is_node
: std::integral_constant<bool,
can_instantiate_to<Node_a, L>::value
|| can_instantiate_to<Node_b, L>::value
|| can_instantiate_to<Node_c, L>::value
> ;


template<typename Node, template<typename...> class Node_template>
constexpr bool is_up_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_up_instantiation_of<
Promote_node<Node>, Node_template>();




template<typename Node, template<typename...> class Node_template>
constexpr bool is_down_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_down_instantiation_of<
Demote_node<Node>, Node_template>();




template<typename T, template<typename...> class Node_template>
constexpr bool converted_node_is_instantiation_of() is_down_instantiation_of<T, Node_template>());



// -- [[ Test ]] -- //

template<typename T,
typename=std::enable_if_t<
converted_node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)

int main()
// Create a types for a stack of layers.
using Stack_c = C<B<A<>>>;
using Partial_stack_b = typename Stack_c::prev_type;
using Partial_stack_a = typename Partial_stack_b::prev_type;

typename Stack_c::node_type c;
typename Partial_stack_a::node_type a;

// Test chained type conversions
c = a; // Node_c->b->a
a = c; // Node_a->b->c

// Test constraining parameter of a function
foo(a);

// Create types for 2nd stack of layers.
using Stack2_c = C<A<>>;
using Partial_stack2_a = typename Stack2_c::prev_type;

// Should be false because Stack2_c::node_type is a node
// but it is not an instantiation of the Node_b template.
std::cout << converted_node_is_instantiation_of<
Stack2_c::node_type, Node_b>();







share|improve this question





















  • How much can concepts simplify this? I haven't looked up how to use concepts yet.
    – R zu
    May 14 at 0:45
















up vote
1
down vote

favorite












Overview



The following is a type system of layers (A, B, C, Null) and nodes for a library.



A version that prints colored text for debugging is on github.



Thanks in advance for reviewing this.




Features



The user can create a stack of layers:



  • The type of a stack can be C<B<A<>>>, B<C<A<>>>, B<A> or C<A>

  • The lowest layer of a stack must be a memory layer (e.g. A in code).

Conversions between nodes produced by any layers of a stack is possible.




  • For examaple, consider a stack C<B<A<>>>:



    • The 3 layers of the stack would create 3 kinds of nodes, called Na, Nb, Nc.


    • Na, Nb, Nc can convert to each other.

    • The conversion should happen stepwise. For example, conversionNa->Nc involves conversions Na->Nb->Nc


    • Na, Nb, Nc are respectively instantiation of class templates Node_a, Node_b, Node_c


    • layer_type::node_type are Na, Nb, Nc for the 3 layers.


Can write functions that only accept instantiation of a node template. This is enabled by std::enable_if_t and traits in the library.




  • is_node<T> checks if type T is a node.


  • converted_node_is_instantiation_of<T, Node_template> checks if some conversion of T is an instantiation of the Node_template.


  • can_instantiate_to<template, T> checks if T is an instantiaion of the template.


Use case



  • Library of stackable layers with proxies for manipulating the layers.


Problem



  • The is_node trait is not quite extensible.


  • Constraining multiple arguments of a function to accept only instantiation of some node_templates is tedious. Example for constraining just one argument:



template<typename T,
typename=std::enable_if_t<
node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)
// convert c to an actual instantiation of Node_c ...




  • A possible alternative is a helper that checks with static_assert. This helper would also handle type conversion of nodes. But that has other problems as well:


// Possible api
void foo(const T& c)
auto c2 = convert_node<Node_c>(c);


// void foo(const T& b) // can't overload this way.
// auto b2 = convert_node<Node_b>(b);
//



  • The compilation error message for conversions between node types is not very clear. Whether a conversion between nodes is possible actually depends on the stack of layers. But the stack of layers is not shown in the error message.


  • Colored error message in run time won't help if the program doesn't compile.


  • No specification for node, const_node, view_of_node, and view_of_const_node.


type_system.cpp



#include <iostream>
#include <type_traits>

// -- [[ Forward declarations ]] -- //
template<class> struct Node_a;
template<class> struct Node_b;
template<class> struct Node_c;
struct Node_null;

template<class, class, int> struct B;
template<class, class> struct C;
struct Null;

// -- [[ Node converters ]] -- //
template<class Self, class Next>
struct Chained_converter
template<class Destination,
class = std::enable_if_t<
std::is_constructible_v<Destination, Next>
&& !std::is_same<Destination, Null>::value
>
>
operator Destination()
return static_cast<Self*>(this)->operator Next();

;

template<class L>
struct Node_converter
: Chained_converter<class L::node_type,
class L::prev_type::node_type>,
Chained_converter<class L::node_type,
class L::next_type::node_type>
;

template<typename Node> using Promote_node = typename
Node::layer_type::next_type::node_type;

template<typename Node> using Demote_node = typename
Node::layer_type::prev_type::node_type;


// -- [[ Node ]] -- //
struct Node_null
using layer_type=Null;
;

template <class Self, class L>
class Node_base : public Node_converter<L>
using next_type = typename L::next_type::node_type;
using prev_type = typename L::prev_type::node_type;
public:
operator prev_type() return prev_type();
operator next_type() return next_type();
;

template<class L>
struct Node_a : public Node_base<Node_a<L>, L>
using layer_type = L;
using Node_base<Node_a<L>, L>::Node_base;
;

template<class L>
struct Node_b : public Node_base<Node_b<L>, L>
using layer_type = L;
using Node_base<Node_b<L>, L>::Node_base;
;

template<class L>
struct Node_c : public Node_base<Node_c<L>, L>
using layer_type = L;
using Node_base<Node_c<L>, L>::Node_base;
;

// -- [[ Layers ]] --
struct Null
using node_type = Node_null;
;

template<class Raw_prev=Null, class Next=Null>
struct A
using self_type = A<Raw_prev, Next>;
using node_type = Node_a<self_type>;
using prev_type = Null;
using next_type = Next;
template<class New_next>
using rebase = A<Raw_prev, New_next>;
;

template<class Raw_prev, class Next=Null, int Parm = 1>
struct B
using self_type = B<Raw_prev, Next, Parm>;
using node_type = Node_b<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next>
using rebase = B<Raw_prev, New_next, Parm>;
;

template<class Raw_prev, class Next=Null>
struct C
using self_type = C<Raw_prev, Next>;
using node_type = Node_c<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next> using rebase = C<Raw_prev, New_next>;
;

// -- [[ Node 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 L>
struct is_node
: std::integral_constant<bool,
can_instantiate_to<Node_a, L>::value
|| can_instantiate_to<Node_b, L>::value
|| can_instantiate_to<Node_c, L>::value
> ;


template<typename Node, template<typename...> class Node_template>
constexpr bool is_up_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_up_instantiation_of<
Promote_node<Node>, Node_template>();




template<typename Node, template<typename...> class Node_template>
constexpr bool is_down_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_down_instantiation_of<
Demote_node<Node>, Node_template>();




template<typename T, template<typename...> class Node_template>
constexpr bool converted_node_is_instantiation_of() is_down_instantiation_of<T, Node_template>());



// -- [[ Test ]] -- //

template<typename T,
typename=std::enable_if_t<
converted_node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)

int main()
// Create a types for a stack of layers.
using Stack_c = C<B<A<>>>;
using Partial_stack_b = typename Stack_c::prev_type;
using Partial_stack_a = typename Partial_stack_b::prev_type;

typename Stack_c::node_type c;
typename Partial_stack_a::node_type a;

// Test chained type conversions
c = a; // Node_c->b->a
a = c; // Node_a->b->c

// Test constraining parameter of a function
foo(a);

// Create types for 2nd stack of layers.
using Stack2_c = C<A<>>;
using Partial_stack2_a = typename Stack2_c::prev_type;

// Should be false because Stack2_c::node_type is a node
// but it is not an instantiation of the Node_b template.
std::cout << converted_node_is_instantiation_of<
Stack2_c::node_type, Node_b>();







share|improve this question





















  • How much can concepts simplify this? I haven't looked up how to use concepts yet.
    – R zu
    May 14 at 0:45












up vote
1
down vote

favorite









up vote
1
down vote

favorite











Overview



The following is a type system of layers (A, B, C, Null) and nodes for a library.



A version that prints colored text for debugging is on github.



Thanks in advance for reviewing this.




Features



The user can create a stack of layers:



  • The type of a stack can be C<B<A<>>>, B<C<A<>>>, B<A> or C<A>

  • The lowest layer of a stack must be a memory layer (e.g. A in code).

Conversions between nodes produced by any layers of a stack is possible.




  • For examaple, consider a stack C<B<A<>>>:



    • The 3 layers of the stack would create 3 kinds of nodes, called Na, Nb, Nc.


    • Na, Nb, Nc can convert to each other.

    • The conversion should happen stepwise. For example, conversionNa->Nc involves conversions Na->Nb->Nc


    • Na, Nb, Nc are respectively instantiation of class templates Node_a, Node_b, Node_c


    • layer_type::node_type are Na, Nb, Nc for the 3 layers.


Can write functions that only accept instantiation of a node template. This is enabled by std::enable_if_t and traits in the library.




  • is_node<T> checks if type T is a node.


  • converted_node_is_instantiation_of<T, Node_template> checks if some conversion of T is an instantiation of the Node_template.


  • can_instantiate_to<template, T> checks if T is an instantiaion of the template.


Use case



  • Library of stackable layers with proxies for manipulating the layers.


Problem



  • The is_node trait is not quite extensible.


  • Constraining multiple arguments of a function to accept only instantiation of some node_templates is tedious. Example for constraining just one argument:



template<typename T,
typename=std::enable_if_t<
node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)
// convert c to an actual instantiation of Node_c ...




  • A possible alternative is a helper that checks with static_assert. This helper would also handle type conversion of nodes. But that has other problems as well:


// Possible api
void foo(const T& c)
auto c2 = convert_node<Node_c>(c);


// void foo(const T& b) // can't overload this way.
// auto b2 = convert_node<Node_b>(b);
//



  • The compilation error message for conversions between node types is not very clear. Whether a conversion between nodes is possible actually depends on the stack of layers. But the stack of layers is not shown in the error message.


  • Colored error message in run time won't help if the program doesn't compile.


  • No specification for node, const_node, view_of_node, and view_of_const_node.


type_system.cpp



#include <iostream>
#include <type_traits>

// -- [[ Forward declarations ]] -- //
template<class> struct Node_a;
template<class> struct Node_b;
template<class> struct Node_c;
struct Node_null;

template<class, class, int> struct B;
template<class, class> struct C;
struct Null;

// -- [[ Node converters ]] -- //
template<class Self, class Next>
struct Chained_converter
template<class Destination,
class = std::enable_if_t<
std::is_constructible_v<Destination, Next>
&& !std::is_same<Destination, Null>::value
>
>
operator Destination()
return static_cast<Self*>(this)->operator Next();

;

template<class L>
struct Node_converter
: Chained_converter<class L::node_type,
class L::prev_type::node_type>,
Chained_converter<class L::node_type,
class L::next_type::node_type>
;

template<typename Node> using Promote_node = typename
Node::layer_type::next_type::node_type;

template<typename Node> using Demote_node = typename
Node::layer_type::prev_type::node_type;


// -- [[ Node ]] -- //
struct Node_null
using layer_type=Null;
;

template <class Self, class L>
class Node_base : public Node_converter<L>
using next_type = typename L::next_type::node_type;
using prev_type = typename L::prev_type::node_type;
public:
operator prev_type() return prev_type();
operator next_type() return next_type();
;

template<class L>
struct Node_a : public Node_base<Node_a<L>, L>
using layer_type = L;
using Node_base<Node_a<L>, L>::Node_base;
;

template<class L>
struct Node_b : public Node_base<Node_b<L>, L>
using layer_type = L;
using Node_base<Node_b<L>, L>::Node_base;
;

template<class L>
struct Node_c : public Node_base<Node_c<L>, L>
using layer_type = L;
using Node_base<Node_c<L>, L>::Node_base;
;

// -- [[ Layers ]] --
struct Null
using node_type = Node_null;
;

template<class Raw_prev=Null, class Next=Null>
struct A
using self_type = A<Raw_prev, Next>;
using node_type = Node_a<self_type>;
using prev_type = Null;
using next_type = Next;
template<class New_next>
using rebase = A<Raw_prev, New_next>;
;

template<class Raw_prev, class Next=Null, int Parm = 1>
struct B
using self_type = B<Raw_prev, Next, Parm>;
using node_type = Node_b<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next>
using rebase = B<Raw_prev, New_next, Parm>;
;

template<class Raw_prev, class Next=Null>
struct C
using self_type = C<Raw_prev, Next>;
using node_type = Node_c<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next> using rebase = C<Raw_prev, New_next>;
;

// -- [[ Node 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 L>
struct is_node
: std::integral_constant<bool,
can_instantiate_to<Node_a, L>::value
|| can_instantiate_to<Node_b, L>::value
|| can_instantiate_to<Node_c, L>::value
> ;


template<typename Node, template<typename...> class Node_template>
constexpr bool is_up_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_up_instantiation_of<
Promote_node<Node>, Node_template>();




template<typename Node, template<typename...> class Node_template>
constexpr bool is_down_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_down_instantiation_of<
Demote_node<Node>, Node_template>();




template<typename T, template<typename...> class Node_template>
constexpr bool converted_node_is_instantiation_of() is_down_instantiation_of<T, Node_template>());



// -- [[ Test ]] -- //

template<typename T,
typename=std::enable_if_t<
converted_node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)

int main()
// Create a types for a stack of layers.
using Stack_c = C<B<A<>>>;
using Partial_stack_b = typename Stack_c::prev_type;
using Partial_stack_a = typename Partial_stack_b::prev_type;

typename Stack_c::node_type c;
typename Partial_stack_a::node_type a;

// Test chained type conversions
c = a; // Node_c->b->a
a = c; // Node_a->b->c

// Test constraining parameter of a function
foo(a);

// Create types for 2nd stack of layers.
using Stack2_c = C<A<>>;
using Partial_stack2_a = typename Stack2_c::prev_type;

// Should be false because Stack2_c::node_type is a node
// but it is not an instantiation of the Node_b template.
std::cout << converted_node_is_instantiation_of<
Stack2_c::node_type, Node_b>();







share|improve this question













Overview



The following is a type system of layers (A, B, C, Null) and nodes for a library.



A version that prints colored text for debugging is on github.



Thanks in advance for reviewing this.




Features



The user can create a stack of layers:



  • The type of a stack can be C<B<A<>>>, B<C<A<>>>, B<A> or C<A>

  • The lowest layer of a stack must be a memory layer (e.g. A in code).

Conversions between nodes produced by any layers of a stack is possible.




  • For examaple, consider a stack C<B<A<>>>:



    • The 3 layers of the stack would create 3 kinds of nodes, called Na, Nb, Nc.


    • Na, Nb, Nc can convert to each other.

    • The conversion should happen stepwise. For example, conversionNa->Nc involves conversions Na->Nb->Nc


    • Na, Nb, Nc are respectively instantiation of class templates Node_a, Node_b, Node_c


    • layer_type::node_type are Na, Nb, Nc for the 3 layers.


Can write functions that only accept instantiation of a node template. This is enabled by std::enable_if_t and traits in the library.




  • is_node<T> checks if type T is a node.


  • converted_node_is_instantiation_of<T, Node_template> checks if some conversion of T is an instantiation of the Node_template.


  • can_instantiate_to<template, T> checks if T is an instantiaion of the template.


Use case



  • Library of stackable layers with proxies for manipulating the layers.


Problem



  • The is_node trait is not quite extensible.


  • Constraining multiple arguments of a function to accept only instantiation of some node_templates is tedious. Example for constraining just one argument:



template<typename T,
typename=std::enable_if_t<
node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)
// convert c to an actual instantiation of Node_c ...




  • A possible alternative is a helper that checks with static_assert. This helper would also handle type conversion of nodes. But that has other problems as well:


// Possible api
void foo(const T& c)
auto c2 = convert_node<Node_c>(c);


// void foo(const T& b) // can't overload this way.
// auto b2 = convert_node<Node_b>(b);
//



  • The compilation error message for conversions between node types is not very clear. Whether a conversion between nodes is possible actually depends on the stack of layers. But the stack of layers is not shown in the error message.


  • Colored error message in run time won't help if the program doesn't compile.


  • No specification for node, const_node, view_of_node, and view_of_const_node.


type_system.cpp



#include <iostream>
#include <type_traits>

// -- [[ Forward declarations ]] -- //
template<class> struct Node_a;
template<class> struct Node_b;
template<class> struct Node_c;
struct Node_null;

template<class, class, int> struct B;
template<class, class> struct C;
struct Null;

// -- [[ Node converters ]] -- //
template<class Self, class Next>
struct Chained_converter
template<class Destination,
class = std::enable_if_t<
std::is_constructible_v<Destination, Next>
&& !std::is_same<Destination, Null>::value
>
>
operator Destination()
return static_cast<Self*>(this)->operator Next();

;

template<class L>
struct Node_converter
: Chained_converter<class L::node_type,
class L::prev_type::node_type>,
Chained_converter<class L::node_type,
class L::next_type::node_type>
;

template<typename Node> using Promote_node = typename
Node::layer_type::next_type::node_type;

template<typename Node> using Demote_node = typename
Node::layer_type::prev_type::node_type;


// -- [[ Node ]] -- //
struct Node_null
using layer_type=Null;
;

template <class Self, class L>
class Node_base : public Node_converter<L>
using next_type = typename L::next_type::node_type;
using prev_type = typename L::prev_type::node_type;
public:
operator prev_type() return prev_type();
operator next_type() return next_type();
;

template<class L>
struct Node_a : public Node_base<Node_a<L>, L>
using layer_type = L;
using Node_base<Node_a<L>, L>::Node_base;
;

template<class L>
struct Node_b : public Node_base<Node_b<L>, L>
using layer_type = L;
using Node_base<Node_b<L>, L>::Node_base;
;

template<class L>
struct Node_c : public Node_base<Node_c<L>, L>
using layer_type = L;
using Node_base<Node_c<L>, L>::Node_base;
;

// -- [[ Layers ]] --
struct Null
using node_type = Node_null;
;

template<class Raw_prev=Null, class Next=Null>
struct A
using self_type = A<Raw_prev, Next>;
using node_type = Node_a<self_type>;
using prev_type = Null;
using next_type = Next;
template<class New_next>
using rebase = A<Raw_prev, New_next>;
;

template<class Raw_prev, class Next=Null, int Parm = 1>
struct B
using self_type = B<Raw_prev, Next, Parm>;
using node_type = Node_b<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next>
using rebase = B<Raw_prev, New_next, Parm>;
;

template<class Raw_prev, class Next=Null>
struct C
using self_type = C<Raw_prev, Next>;
using node_type = Node_c<self_type>;
using prev_type = typename Raw_prev::template rebase<self_type>;
using next_type = Next;
template<class New_next> using rebase = C<Raw_prev, New_next>;
;

// -- [[ Node 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 L>
struct is_node
: std::integral_constant<bool,
can_instantiate_to<Node_a, L>::value
|| can_instantiate_to<Node_b, L>::value
|| can_instantiate_to<Node_c, L>::value
> ;


template<typename Node, template<typename...> class Node_template>
constexpr bool is_up_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_up_instantiation_of<
Promote_node<Node>, Node_template>();




template<typename Node, template<typename...> class Node_template>
constexpr bool is_down_instantiation_of()
if constexpr (std::is_same<Node, Node_null>::value)
return false;
else
if constexpr (can_instantiate_to<Node_template, Node>::value)
return true;
else
return is_down_instantiation_of<
Demote_node<Node>, Node_template>();




template<typename T, template<typename...> class Node_template>
constexpr bool converted_node_is_instantiation_of() is_down_instantiation_of<T, Node_template>());



// -- [[ Test ]] -- //

template<typename T,
typename=std::enable_if_t<
converted_node_is_instantiation_of<T, Node_c>()> >
void foo(const T& c)

int main()
// Create a types for a stack of layers.
using Stack_c = C<B<A<>>>;
using Partial_stack_b = typename Stack_c::prev_type;
using Partial_stack_a = typename Partial_stack_b::prev_type;

typename Stack_c::node_type c;
typename Partial_stack_a::node_type a;

// Test chained type conversions
c = a; // Node_c->b->a
a = c; // Node_a->b->c

// Test constraining parameter of a function
foo(a);

// Create types for 2nd stack of layers.
using Stack2_c = C<A<>>;
using Partial_stack2_a = typename Stack2_c::prev_type;

// Should be false because Stack2_c::node_type is a node
// but it is not an instantiation of the Node_b template.
std::cout << converted_node_is_instantiation_of<
Stack2_c::node_type, Node_b>();









share|improve this question












share|improve this question




share|improve this question








edited May 14 at 0:40
























asked May 13 at 22:18









R zu

2026




2026











  • How much can concepts simplify this? I haven't looked up how to use concepts yet.
    – R zu
    May 14 at 0:45
















  • How much can concepts simplify this? I haven't looked up how to use concepts yet.
    – R zu
    May 14 at 0:45















How much can concepts simplify this? I haven't looked up how to use concepts yet.
– R zu
May 14 at 0:45




How much can concepts simplify this? I haven't looked up how to use concepts yet.
– R zu
May 14 at 0:45















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194326%2ftype-system-for-layers-and-nodes%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194326%2ftype-system-for-layers-and-nodes%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Chat program with C++ and SFML

Function to Return a JSON Like Objects Using VBA Collections and Arrays

Will my employers contract hold up in court?