嵌套在模板类 C++ 中的非模板化类

Nested not templated class inside a template class C++

提问人:Jay 提问时间:11/11/2023 最后编辑:user12002570Jay 更新时间:11/11/2023 访问量:102

问:

这是我的代码

头.h


template <class T>
class Ext;

template <class T>
void fun(const Ext<T>&);

template <class T>
class Ext {
    friend void fun<T>(const Ext<T>&);

   private:
    class Inner;

    Inner* p;
};

template <class T>
void fun2(const typename Ext<T>::Inner&);

template <class T>
class Ext<T>::Inner {
    friend class Ext<T>;
    friend void fun<T>(const Ext<T>&);
    friend void fun2<T>(const typename Ext<T>::Inner&);

   private:
    Inner* q;
    int a;
    Inner() : a(1) {}
};

template <class T>
void fun2(const typename Ext<T>::Inner& i) {
    std::cout << i.a << std::endl;
}

template <class T>
void fun(const Ext<T>& e) {
    typename Ext<T>::Inner y;
    y.a = 3;
    fun2<T>(y);
}

main.cpp

int main() {
    Ext<int> x;
    fun(x);
}

g++ 和(见下文)clang 给出一个

class Ext<int>::Inner’ is private within this context

所以我的问题是:有没有办法在不公开内部阶级的情况下做到这一点? 为什么如果我用重载运算符替换 fun anf fun2<<那么它甚至可以使用内部类 private(仅使用 CLANG)进行编译?喜欢这个

头.h

#include <iostream>

template <class T>
class Ext;

template <class T>
std::ostream& operator<<(std::ostream&, const Ext<T>&);

template <class T>
class Ext {
    friend std::ostream& operator<< <T>(std::ostream&, const Ext<T>&);

   private:
    class Inner;

    Inner* p;
};

template <class T>
std::ostream& operator<<(std::ostream&, const typename Ext<T>::Inner&);

template <class T>
class Ext<T>::Inner {
    friend class Ext<T>;
    friend std::ostream& operator<< <T>(std::ostream&, const typename Ext<T>::Inner&);

   private:
    Inner* q;
    int a;
    Inner() : a(1) {}
};

template <class T>
std::ostream& operator<<(std::ostream& os, const typename Ext<T>::Inner& n) {
    return os << n.a << " ";
}

template <class T>
std::ostream& operator<<(std::ostream& os, const Ext<T>& t) {
    os << "[ ";
    operator<< <T>(os, *(t.p));
    os << "] ";
    return os;
}

main.cpp

int main() {
    Ext<int> x;
    std::cout << x << std::endl;
}

我尝试使用不同的编译器进行编译,但如果我不使用 clang 进行编译,则没有任何效果,在这种情况下,它仅在函数是运算符的重载时进行编译

C++ 编译器错误 友元 模板

评论

0赞 user12002570 11/11/2023
你需要让类模板也是一个朋友。此外,您需要添加到每个友元声明中。这在下面的答案中进行了解释。进行这些更改后,程序将在所有编译器中运行Exttemplate<typename U>
0赞 user12002570 11/11/2023
此外,我建议每篇文章只问一个问题。第二个代码片段应该作为不同的问题 imo 提出。C++ 是一种非常复杂的语言,因此试图通过反复试验来理解它并不是学习它的正确方法。此外,一本好的 c++ 书应该会有所帮助。

答:

1赞 user12002570 11/11/2023 #1

有没有办法在不公开内部阶级的情况下做到这一点?

是的,但是代码存在几个问题,下面将解释和解决所有这些问题。

首先,ship 在 C++ 中不是关联的。这意味着您需要在类模板内部添加一个友元模板声明,如下面的代码所示。friendfun2Ext

其次,您当前拥有的好友声明是非模板好友声明。但是,由于 和 是模板,因此您需要将它们更改为友元模板声明,这是通过添加如下所示的代码来完成的。funfun2template<typename U>

注释也添加到下面的程序中,以便更容易发现更改:

#include <iostream>
template <class T>
class Ext;

template <class T>
void fun(const Ext<T>&);

template <class T>
class Ext {
    template<typename U> //added this template<typename U>
    friend void fun(const Ext<U>&); 
    //added this friend template declaration
    template <class U>
    friend void fun2(const typename Ext<U>::Inner& i);  
   private:
    class Inner;

    Inner* p;
};

template <class T>
void fun2(const typename Ext<T>::Inner&);
  
template <class T>
class Ext<T>::Inner {

    template<typename U>  //added this template<typename U>
    friend void fun(const Ext<U>&);  
    
    template <class U>   //added this template<typename U>
    friend void fun2(const typename Ext<U>::Inner& i);         
 
   private:
    Inner* q; 
    int a;
    Inner() : a(1) {} 
};

template <class T>
void fun2(const typename Ext<T>::Inner& i) {
    std::cout << i.a << std::endl; 
} 
 
template <class T>
void fun(const Ext<T>& e) {
    typename Ext<T>::Inner y;  
    y.a = 3;
    fun2<T>(y);       
}

int main() {
    Ext<int> x;
    fun(x);
} 

工作演示

现在该程序适用于所有编译器。

评论

0赞 Jay 11/12/2023
是的,但是如果我做 fun 和 fun2 friend 模板声明,那么无论模板参数如何,它们都是 Ext 的朋友。