У меня есть набор базовых классов графов, которые используют CRTP для работы с производными классами графов. У меня есть класс шаблона GraphTypes
, который принимает производные классы графов в качестве параметров шаблона, а затем базовые классы графов, такие как Edge
и Node
, принимают GraphTypes
в качестве параметра шаблона.
Внутри классов базовых графов я использую псевдонимы типов (using
), чтобы упростить использование производных классов. Я хотел бы, чтобы эти псевдонимы типов были видны только внутри классов базовых графов, а не в классах производных графов. Это возможно?
См. код ниже для настройки и проблемы, когда псевдоним типа в базовом классе графа используется в производном классе.
namespace DirectedGraph {
template<class NodeT, class EdgeT>
class GraphTypes {
public:
using NodeType = NodeT;
using EdgeType = EdgeT;
};
template<class GraphTypes>
class Edge {
private:
using NodeType = typename GraphTypes::NodeType;
using EdgeType = typename GraphTypes::EdgeType;
public:
auto This() -> EdgeType &;
};
}
namespace MyGraph {
class Node;
class Edge;
using GraphTypes = DirectedGraph::GraphTypes<Node, Edge>;
enum class EdgeType { A, B, C };
class Edge : public DirectedGraph::Edge<GraphTypes> {
Edge(EdgeType Type); // `EdgeType` is interpreted as the type alias `DirectedGraph::Edge::EdgeType` instead of the enum `MyGraph::EdgeType`.
};
}
Вы всегда можете уточнить полное пространство имен
namespace MyGraph {
class Node;
class Edge;
using GraphTypes = DirectedGraph::GraphTypes<Node, Edge>;
enum class EdgeType { A, B, C };
class Edge : public DirectedGraph::Edge<GraphTypes> {
Edge(::MyGraph::EdgeType Type);
// ^^^^^^^^^^^^^^^^^^
// or
// Edge(MyGraph::EdgeType Type);
};
}
Или используйте разные имена для типов/псевдонимов типов, чтобы избежать путаницы.
При этом, если вы настаиваете на сохранении имен как есть и не хотите использовать их из базового класса, предоставьте косвенность этим типам псевдонимов с помощью класса/структуры.
namespace DirectedGraph
{
// ....
template<class GraphTypes>
class Edge {
private:
public:
struct Internal { // moved under the Internal struct!
using NodeType = typename GraphTypes::NodeType;
using EdgeType = typename GraphTypes::EdgeType;
};
auto This() -> typename Internal::EdgeType&;
};
}
namespace MyGraph {
// ....
enum class EdgeType { A, B, C };
class Edge : public DirectedGraph::Edge<GraphTypes> {
Edge(EdgeType Type); //Now you can!
};
}
Я предполагаю, что вы не хотите переименовывать EdgeType
в Edge
. Если бы вы хотели это сделать, вы могли бы просто использовать разные имена для разных псевдонимов и не сталкиваться с этой проблемой.
Чтобы решить эту проблему, не меняя никаких имен, вы можете затенить DirectedGraph::Edge<T>::EdgeType
, объявив другой псевдоним внутри MyGraph::Edge
:
class Edge : public DirectedGraph::Edge<GraphTypes> {
// possibly make this private
using EdgeType = MyGraph::EdgeType;
// we could also use MyGraph::EdgeType directly here, but that would be uglier
Edge(EdgeType Type);
};
Псевдоним MyGraph::Edge::EdgeType
будет скрывать любые объявления в области действия базового класса и в окружающей области, поэтому вы можете устранить неоднозначность таким образом.
Это не ответит на ваш вопрос, но я насчитываю 3 разных значения для
GraphTypes
. Это может быть законно, но это сбивает с толку (по крайней мере, для меня). Использование разных имен может помочь прояснить проблему...