C++ 如何将模板类X的模板成员函数声明为嵌套类X::Y的朋友

C++ 如何将模板类X的模板成员函数声明为嵌套类X::Y的朋友,c++,templates,inner-classes,friend-function,C++,Templates,Inner Classes,Friend Function,我有一个模板类。它有一个模板功能。两者都采用不同的模板参数。有一个内部类需要与封闭类的模板函数交朋友。编译器错误比比皆是。下面的玩具示例显示了我的问题 首先,当然要汇编以下内容(VS 2017): 现在我得到一个编译器错误:错误C3856:'Class1::Func':类不是类模板 在嵌套类时,我使用了各种方法来声明friend,但我无法编译它。可能没有办法做我想做的事 请注意,我尝试执行的操作(在实际代码中,而不是在这个玩具示例中)的语义是这样的:Func应该是一个成员函数。这与迭代器或运算符

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

首先,当然要汇编以下内容(VS 2017):

现在我得到一个编译器错误:
错误C3856:'Class1::Func':类不是类模板

在嵌套类时,我使用了各种方法来声明friend,但我无法编译它。可能没有办法做我想做的事

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

更糟糕的是,根据我的设计,将所有
Class1
声明为
Class2
的朋友是可以的(这样做可以让我解决这个问题)
Class2
是一个与
Class1
完全耦合的小助手类;它的所有特殊成员save the destructor和move ctor都是私有的或已删除的,并且
Class1::Func
是唯一实例化
Class2
(并通过move ctor将其返回给
Class1
的用户)的对象。因此,尽管将整个
Class1
交为好友并不理想,但在必要时还是可以的


提前感谢。

我第一次尝试在gcc HEAD 9.0.0上复制OP的问题,得到:

开始
prog.cc:17:23:错误:模板参数“T”的声明阴影模板参数
17 |模板//此处出现编译器错误。
|                       ^~~~~~~~
prog.cc:1:11:注意:此处声明了模板参数“T”
1 |模板
|           ^~~~~~~~
prog.cc:在函数“int main()”中:
程序cc:25:17:警告:未使用的变量“c1”[-Wunused variable]
25 | c1类;
|                 ^~
1.
完成
修复很简单–
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;
}
再次测试:

开始
prog.cc:在函数“int main()”中:
程序cc:24:17:警告:未使用的变量“c1”[-Wunused variable]
24 | c1类;
|                 ^~
0
完成

这似乎是MSVS编译器中的一个错误。gcc和clang都接受您的代码和Scheff的更正。作为临时解决办法,可以使用ifdef:

#ifdef _MSC_VER
    friend class Class1;
#else
    template <typename U>
    friend void Class1::Func(U& x);
#endif
\ifdef\u MSC\u VER
朋友班1;
#否则
模板
friend-void类1::Func(U&x);
#恩迪夫

添加。

似乎是MSVS的一个bug,OP的代码(在
friend
声明中的
template
被删除)没有编译。@Evgeny您在VS2017中试过吗?(我只在g++按预期工作的地方使用了它。)我在OP的问题中忽略了这一点,并假设他/她没有检查这一点(第二个工作变体)。我在最新的VS2018测试版中试用了它。在您的第一个块中,您可能错过了
friend void Class1::Func(U&x)中的
@Evgeny AFAIK,如果省略了模板参数,则(在
Class1
的定义中)
Class1
=
Class1
。我不得不承认,这与
template
…@scheff一起没有多大意义,多亏了你和大家——我曾尝试将模板参数更改为不同的参数(同时尝试了许多其他事情),但仍然没有成功。这似乎是由于VS中的一个bug造成的。遗憾的是,这段代码的真实版本通常是用gcc编译的,但我把我的gcc计算机留在了办公室,在家里修改代码。所以如果我不是健忘的话,我甚至不用写这篇文章。再次感谢。我刚刚认识到
模板void Class1::Func(U&x){}
公共的
。所以,把
friend
的东西扔了吧。(我在开玩笑。)如果你的MCVE是
私人的
,它会更有意义。我认为这是真正的意图。@scheff-Ha,是的,这只是一个玩具示例,因此某些类成员的访问级别与实际代码中的不同。感谢您验证这是一个bug。
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;
}
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;
}
#ifdef _MSC_VER
    friend class Class1;
#else
    template <typename U>
    friend void Class1::Func(U& x);
#endif