如何使类型别名对派生类不可见?

How to make type alias invisible to derived classes?

提问人:Magnar Myrtveit 提问时间:6/20/2023 最后编辑:JeJoMagnar Myrtveit 更新时间:6/21/2023 访问量:68

问:

我有一组基图类,用于处理派生的图类。我有一个模板类,它把派生的图类作为模板参数,然后把基图类(如和)作为模板参数。CRTPGraphTypesEdgeNodeGraphTypes

在基类中,我使用类型别名 () 来简化派生类的使用。我希望这些类型别名仅在基图类中可见,而在派生的图类中不可见。这可能吗?graphusing

有关设置,请参阅下面的代码,以及在派生类中使用基图类中的类型别名的问题。

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`.
    };
}
C++ 模板 CRTP 类型别名类 模板

评论

0赞 Oersted 6/20/2023
它不会回答你的问题,但我计算了 3 种不同的含义。这可能是合法的,但它令人困惑(至少对我来说是这样)。使用不同的名称可能有助于澄清问题......GraphTypes

答:

3赞 JeJo 6/20/2023 #1

始终可以限定完整命名空间

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!
    };
}

演示

1赞 Jan Schultke 6/20/2023 #2

我假设您不想重命名.如果您愿意这样做,您可以为不同的别名使用不同的名称,而不会遇到此问题。EdgeTypeEdge

要在不更改任何名称的情况下解决此问题,您可以通过在以下位置声明另一个别名来进行影子:DirectedGraph::Edge<T>::EdgeTypeMyGraph::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