如何在其他模板类中声明一个模板友元类?

How to declare a template friend class inside other template class?

提问人:getsuga 提问时间:3/9/2023 更新时间:3/9/2023 访问量:140

问:

  • 你好。我正在尝试实现双链表。我有一个类和类作为容器中元素的 shell,我更喜欢作为而不是作为 ,因为我希望节点字段在外部无法访问,但我还需要在类中访问它们,因此我选择将其作为朋友类来改进封装,而不是制作 getter 和 setter。linked_listDListNodeDListNodeclassstructlinked_listlinked_listDLinstNode

  • 问题:我按照我的计划做了这样的事:

template <
    class Dty_
>
class DListNode {
public:

// ...

template <class ...> friend class linked_list; // line 168
// template <class ...> friend class linked_list<Dty_, DListNode<Dty_>, std::allocator<Dty_>>; full specialization doesn't work too

protected:
// ...
};



template <
    class Ty_,
    template <class ...> class List_node_ = DListNode,
    class Alloc_ = std::allocator<Ty_>
>
class linked_list { // line 13

// ...

};
  • 并在第 13 行出现错误:“使用 3 个模板参数重新声明”

  • 完整的错误文本:

C:\Users\averu\github-local\base\ds\list\list.cpp:13:7: error: redeclared with 3 template parameters
   13 | class linked_list { // biderectional double linked list
      |       ^~~~~~~~~~~
In file included from C:\Users\averu\github-local\base\ds\list\iterator.cpp:2,
                 from C:\Users\averu\github-local\base\ds\list\list.cpp:1:
C:\Users\averu\github-local\base\ds\list\node.cpp:168:39: note: previous declaration 'template<class ...> class linked_list' used 1 template parameter
  168 |     template <class ...> friend class linked_list;
      |     
  • 问题:
    1. 如何以正确的方式申报我的计划?
    2. 有没有更好的方法可以做到这一点?
    3. 还有其他建议吗?

正如你所看到的,我正在尝试使用可变参数模板,但它不起作用。那么,也许我需要通过声明来声明类转发,然后该怎么做呢?linked_listusing

那里有完整的代码

使用 friend-class C++ variadic-templates

评论

1赞 joergbrech 3/9/2023
我没有看过你的github代码,但感觉你的实现过于复杂。您真的需要模板模板参数吗?您已经传入了一个类型,大概是节点持有的类型,因此linked_list确切地知道其节点的节点类型。在那里拥有自由会增加不必要的复杂性,并引入滥用模式。如果有人声明 ?linked_listlinked_list<double, DListNode<std::string>>
1赞 user10 3/9/2023
List 不是节点的朋友,而是它的所有者,因此 Node 作为结构将在通过 List 公共方法作为私有头/尾进行管理时执行。列表应该只关心Dty_类型,而不关心其他任何类型。<Dty_,DListNode<Dty_> std::allocator<Dty_>只能替换为一个对所有Dty_通用的。
0赞 getsuga 3/9/2023
@joergbrech,是的,这对我来说有点复杂,但我的目标是为自己制造问题,然后尝试解决它们)) (我想成为一名优秀的专家) 非常感谢您在我的代码中发现此错误,您能告诉我如何解决这个问题吗?当然,其中一个选项是从我的代码中删除字符串。但是有没有其他解决方案可以与这条线兼容呢?我希望它可以打电话和template <class ...> class List_node_ = DListNodelinked_list<int>linked_list<int, other_node>
0赞 getsuga 3/9/2023
@fggrh,你的话很合乎逻辑,谢谢!据我了解,您建议将实现放在类中?struct DListNodelinked_list

答:

2赞 joergbrech 3/9/2023 #1

friend 类的声明使用与 的定义不同的模板参数。您需要像这样将其声明为朋友:linked_list

class DListNode {
public:
    template <class, template <class...> class, class> friend class linked_list;
};

因为有一个类模板参数,后跟一个模板模板参数,后跟另一个类参数。linked_list

https://godbolt.org/z/hxhP396nv

评论

0赞 getsuga 3/9/2023
这对我有帮助,非常感谢你的例子!但是你能问我,为什么你用而不是或者至少给出一个我可以读到的参考?List_node_<T> const& nconst List_node_<T>& n
0赞 joergbrech 3/9/2023
两种符号是可以互换的,这实际上是个人喜好的问题。
0赞 user10 3/9/2023
引用始终是 const,所以无论你把 const 放在哪里,都意味着 const ref 到 const 引用
0赞 getsuga 3/9/2023
@fggrh,你的意思是那什么也做不了,因为和是一样的东西吗?const&const&&
0赞 user10 3/9/2023
不。const& 表示 const ref 到 const 对象,其中 & 表示 const ref 到非 const 对象。由于 ref const 根据定义,唯一可以更改为 const 的是引用对象,这就是为什么 const 位置没有任何区别的原因,