How to explicitly instantiate a template class that has a nested class with a friend function (C++)

后端 未结 2 998
旧时难觅i
旧时难觅i 2021-02-14 11:07

Probably been asked before, but all this is approaching the limit of my comprehension and cognizance of C++, so I\'m a little slow in understanding what\'s being talked about an

2条回答
  •  有刺的猬
    2021-02-14 11:28

    The problem is not with friend.

    The problem is with this function itself:

    template 
    void swap(typename Foo::Bar& b1, typename Foo::Bar& b2) {} // line 26
    

    Deducing template parameter T from nested class is not possible, see: Output a nested class inside a template or even better this answer: https://stackoverflow.com/a/4092248/1463922

    To give example why it cannot be done, consider this function:

    template 
    void foo(typename A::Bar);
    

    And this A definition:

    template 
    struct A { typedef int Bar; };
    

    And this call:

    int a;
    foo(a);
    

    What is T in this example? Is it int because A::Bar is int, OR float because A::Bar is int too OR whatever you want.... The question is what function you are calling foo(int) or foo(int) or ...

    Or to give example more closer to question:

    template 
    struct Foo {
       struct Bar {}; 
    };
    

    It seems that compiler should have no problems with resolving this:

    template 
    void resolve(typename Foo::Bar*);
    

    But compiler even here has problems because it is not sure if specialization of some other class will not use inner struct of other class, like this:

    template 
    struct Foo {
       typedef Foo::Bar Bar; 
    };
    

    So for:

    Foo::Bar b;
    resolve(&b);
    

    Compiler has no chance to know which version to call:

    resolve(Foo::Bar*);
    // or 
    resolve(Foo::Bar*);
    //          ^   
    

    What can I advice you - use inline friend - but implement it with some other template class. This works - but I am sure this is a little over-engineered:

    template 
    class ImplementSwap;
    
    template 
    class Foo {
        public:
        struct Bar {
            int a;
            Bar() {}
            ~Bar() {}
            friend class ImplementSwap>;
            friend void swap(Foo::Bar& b1, Foo::Bar& b2)
            {  ImplementSwap>::doSwap(b1, b2); }
            Bar(Bar&& b)  { swap(*this, b); }
    
        };
    };
    
    template 
    class ImplementSwap> {
    public:
       static void doSwap(typename Foo::Bar&,typename Foo::Bar&);
    };
    
    template 
    void ImplementSwap>::doSwap(typename Foo::Bar&,typename Foo::Bar&) 
    {
      // this one is not inline....
    }
    

    I made Bar public to do this test:

    Foo::Bar a = Foo::Bar(); // move constructor
    
    int main() {
      swap(a,a); // explicit swap
    }
    

    [OLD] My previous answer was completely wrong, and first comments refer to it.

    friend void swap<>(typename Foo::Bar&, typename Foo::Bar&);
    //              ^^
    

    [/OLD]

提交回复
热议问题