【问题标题】:Class template with template class friend, what's really going on here?类模板与模板类朋友,这里到底发生了什么?
【发布时间】:2012-02-16 13:26:05
【问题描述】:

假设我正在为二叉树创建一个类BT,并且我有一个描述树元素的类BE,类似于

template<class T> class BE {
    T *data;
    BE *l, *r;
public:
...
    template<class U> friend class BT;
};

template<class T> class BT {
    BE<T> *root;
public:
...
private:
...
};

这似乎有效;但是我对下面发生的事情有疑问。

我最初试图将朋友声明为

template<class T> friend class BT;

但是这里似乎有必要使用U(或T 以外的其他东西),这是为什么呢?这是否暗示任何特定的BT 是任何特定BE 类的朋友?

关于模板和朋友的 IBM 页面提供了函数但没有类的不同类型朋友关系的示例(并且猜测语法尚未收敛到解决方案上)。我更愿意了解如何为我希望定义的朋友关系类型获得正确的规范。

【问题讨论】:

    标签: c++ class templates


    【解决方案1】:
    template<class T> class BE{
      template<class T> friend class BT;
    };
    

    不允许,因为模板参数不能相互影响。嵌套模板必须具有不同的模板参数名称。


    template<typename T>
    struct foo {
      template<typename U>
      friend class bar;
    };
    

    这意味着barfoo 的朋友,无论bar 的模板参数如何。 bar&lt;char&gt;bar&lt;int&gt;bar&lt;float&gt; 和任何其他 bar 将成为 foo&lt;char&gt; 的朋友。


    template<typename T>
    struct foo {
      friend class bar<T>;
    };
    

    这意味着当bar 的模板参数匹配foo 时,barfoo 的朋友。只有bar&lt;char&gt; 会成为foo&lt;char&gt; 的朋友。


    在您的情况下,friend class bar&lt;T&gt;; 应该就足够了。

    【讨论】:

    • 我的代码友元类 BT 中的这种构造会为友元行错误抛出一个错误:'BT' 不是模板,即使它后来被声明为模板 class BT { 。 .. }
    • 所以秘密是我需要转发声明BT才能使用朋友类BT; BE 中的行,但不用于模板 朋友类 BT;。感谢您的帮助!
    • 更具体地说:你必须在BE的定义之前转发声明template&lt;typename T&gt; class BT;,然后在inside类中使用friend class BT&lt;T&gt;;是。
    【解决方案2】:

    为了和另一个同类型的结构体交朋友:

    #include <iostream>
    
    template<typename T_>
    struct Foo
    {
        // Without this next line source.value_ later would be inaccessible.
        template<typename> friend struct Foo;
    
        Foo(T_ value) : value_(value) {}
    
        template <typename AltT>
        void display(AltT &&source) const
        {
            std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
        }
    
    protected:
        T_ value_;
    };
    
    int main()
    {
        Foo<int> foo1(5);
        Foo<std::string> foo2("banana");
    
        foo1.display(foo2);
    
        return 0;
    }
    

    输出如下:

    My value is 5 and my friend's value is banana. 
    

    template&lt;typename&gt; friend struct Foo;中你不应该在typename/class之后写T,否则会导致模板参数阴影错误。

    【讨论】:

    • 正是我想要的! ;)
    【解决方案3】:

    不必为参数命名,因此重构时故障点更少:

         template <typename _KeyT, typename _ValueT> class hash_map_iterator{
           template <typename, typename, int> friend class hash_map;
           ...
    

    【讨论】:

      【解决方案4】:

      在我的情况下,这个解决方案可以正常工作:

      template <typename T>
      class DerivedClass1 : public BaseClass1 {
        template<class T> friend class DerivedClass2;
      private:
       int a;
      };
      
      template <typename T>
      class DerivedClass2 : public BaseClass1 {
        void method() { this->i;}
      };
      

      希望对你有所帮助。

      【讨论】:

      • 当您隐藏模板参数并且不使用 DerivedClass2 的朋友访问 DerivedClass1 时,该解决方案应该如何正常工作?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-29
      • 2011-10-14
      • 2014-10-03
      • 2012-03-14
      • 1970-01-01
      • 1970-01-01
      • 2011-03-18
      相关资源
      最近更新 更多