Сделать псевдоним типа невидимым для производных классов

У меня есть набор базовых классов графов, которые используют 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`.
  };
}

Это не ответит на ваш вопрос, но я насчитываю 3 разных значения для GraphTypes. Это может быть законно, но это сбивает с толку (по крайней мере, для меня). Использование разных имен может помочь прояснить проблему...

Oersted 20.06.2023 14:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы всегда можете уточнить полное пространство имен

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 будет скрывать любые объявления в области действия базового класса и в окружающей области, поэтому вы можете устранить неоднозначность таким образом.

Другие вопросы по теме