首页 > 解决方案 > 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的朋友

问题描述

我有一个模板类。它具有模板功能。两者都采用不同的模板参数。有一个内部类需要与封闭类的模板函数交朋友。编译器错误比比皆是。以下玩具示例显示了我的问题。

首先,当然会编译以下内容(VS 2017):

template <typename T>
class Class1
{
    public:
        Class1() = default;
        ~Class1() = default;

        template <typename U>
        void Func(U& x) {};
};

class Class2
{
    public:
        Class2() = default;
        ~Class2() = default;

        template <typename T>
        template <typename U>
        friend void Class1<T>::Func(U& x);
};

int main()
{
    Class1<int> c1;
    return 0;
}

现在让我们在没有其他更改的情况下Class2进入:Class1

template <typename T>
class Class1
{
    public:
        Class1() = default;
        ~Class1() = default;

        template <typename U>
        void Func(U& x){};

    class Class2
    {
        public:
            Class2() = default;
            ~Class2() = default;

            template <typename T> //Compiler error here.
            template <typename U>
            friend void Class1::Func(U& x);
    };
};

int main()
{
    Class1<int> c1;
    return 0;
}

现在我得到一个编译器错误:error C3856: 'Class1<T>::Func': class is not a class template

当类嵌套时,我尝试了各种方法来声明朋友,但我无法编译它。有可能没有办法做我想做的事情。

请注意,我正在尝试做的事情的语义(在真实代码中,而不是这个玩具示例中)是这样的,即 Func 应该是一个成员函数。这与迭代器或运算符无关,它们当然通常是非成员函数。我在这里看到了一些类似的问题,但它们通常与迭代器或运算符有关,我还没有找到适合我的解决方案的问题。

更糟的是,考虑到我的设计,声明所有Class1朋友都是可以的Class2(这样做可以让我解决这个问题)。Class2是一个完全耦合到的小助手类Class1;它的所有特殊成员,保存析构函数和移动 ctor,要么是私有的,要么是已删除的,并且Class1::Func是唯一实例化的东西Class2(并通过 move ctor 将其返回给 的用户Class1)。因此,虽然与整个Class1.

提前致谢。

标签: c++templatesinner-classesfriend-function

解决方案


我首先尝试使用 gcc HEAD 9.0.0 重现 OP 的问题wandbox.org并得到:

Start

prog.cc:17:23: error: declaration of template parameter 'T' shadows template parameter
17 |             template <typename T> //Compiler error here.
   |                       ^~~~~~~~
prog.cc:1:11: note: template parameter 'T' declared here
1 | template <typename T>
  |           ^~~~~~~~
prog.cc: In function 'int main()':
prog.cc:25:17: warning: unused variable 'c1' [-Wunused-variable]
25 |     Class1<int> c1;
   |                 ^~

1

Finish

修复很简单——T已经是模板参数,必须在嵌套friend声明中重命名:

template <typename T>
class Class1
{
    public:
        Class1() = default;
        ~Class1() = default;

        template <typename U>
        void Func(U& x){};

    class Class2
    {
        public:
            Class2() = default;
            ~Class2() = default;

            template <typename T1> //Compiler error gone.
            template <typename U>
            friend void Class1<T1>::Func(U& x);
    };
};

int main()
{
    Class1<int> c1;
    return 0;
}

再次测试wandbox.org

Start

prog.cc: In function 'int main()':
prog.cc:25:17: warning: unused variable 'c1' [-Wunused-variable]
25 |     Class1<int> c1;
   |                 ^~

0

Finish

如果打算像这样friend void Class1::Func(U& x);依赖于相同的模板参数,那将是替代解决方案:TClass1

template <typename T>
class Class1
{
    public:
        Class1() = default;
        ~Class1() = default;

        template <typename U>
        void Func(U& x){};

    class Class2
    {
        public:
            Class2() = default;
            ~Class2() = default;

            template <typename U>
            friend void Class1::Func(U& x);
    };
};

int main()
{
    Class1<int> c1;
    return 0;
}

再次测试wandbox.org

Start

prog.cc: In function 'int main()':
prog.cc:24:17: warning: unused variable 'c1' [-Wunused-variable]
24 |     Class1<int> c1;
   |                 ^~

0

Finish

推荐阅读