1
  • Hello. I'm trying to implement double linked list. I have a linked_list class and DListNode class as a shell for elements in my container and I prefer DListNode as a class rather than as a struct, because I want node fields to be inaccessible outside, but I also need to get an access to them in a linked_list class, so instead of making getters and setters I have chosen to make linked_list as a friend class for DLinstNode to improve encapsulation.

  • Problem: I did what I planned like this:

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

// ...

};
  • And got an error in line 13: "redeclared with 3 template parameters"

  • The full error text:

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;
      |     
  • Questions:
    1. How to declare what I planned in a right way?
    2. Is there any better way to do this?
    3. Any other recommendations?

As you can see there I'm trying to use variadic template, but it doesn't work. So, perhaps I need to declare class linked_list forward via using declaration how then do it?

full code there

getsuga
  • 15
  • 5
  • 1
    I haven't looked at your github code, but it feels like your `linked_list` implementation is overly complicated. Do you really need the template template parameter? You already pass in a type, presumably the one held by the nodes, so the linked_list knows exactly the node type of its nodes. Having freedom there adds unnecessary complexity and introduces modes of misuse. What happens, if someone declares a `linked_list>`? – joergbrech Mar 09 '23 at 11:32
  • 1
    List is not a friend of node but its owner so Node as struct will do while managed as private head/tail by List public methods. List should care only about Dty_ type and nothing else. , std::allocator can be replaced by only one common to all Dty_. – user10 Mar 09 '23 at 11:47
  • @joergbrech, yeah, It's a little complicated for me, but my goal is to create problems for myself, and then try to solve them)) (I want to become a good specialist) Thank you so much for finding this error in my code, could you tell me how I can fix this? Of course, one of the options is to remove the string `template class List_node_ = DListNode` from my code. But is there another solution that is compatible with this line? I want it to be possible to call `linked_list` and `linked_list` – getsuga Mar 09 '23 at 12:09
  • @fggrh, your remark is very logical, thanks! As I understand, you propose to put the implementation of `struct DListNode` inside the `linked_list` class? – getsuga Mar 09 '23 at 12:16

1 Answers1

2

You declaration of the friend class uses different template arguments than the definition of linked_list. You need to declare it as a friend like so:

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

becaus linked_list has one class template argument, followed by a template template argument, followed by another class argument.

https://godbolt.org/z/hxhP396nv

joergbrech
  • 2,056
  • 1
  • 5
  • 17
  • It helps me, thanks a lot especially for your example! But could you ask me, why you use `List_node_ const& n` instead of `const List_node_& n` or at least give a ref where I can read about that? – getsuga Mar 09 '23 at 11:51
  • Both notations are interchangeable, it's really a question of personal preference. – joergbrech Mar 09 '23 at 12:13
  • Reference is always const so wherever you put const will mean const ref to const referenced – user10 Mar 09 '23 at 12:37
  • @fggrh, do you mean that `const&` doesn't make anything, because of `const&` and `&` are the same things? – getsuga Mar 09 '23 at 13:01
  • No. const& means const ref to const object where & means const ref to non const object. Since ref const by definition the only thing that can be changed to const is referenced object that's why const position doesn't make any difference, – user10 Mar 09 '23 at 13:19