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

时间:2018-08-23 04:22:01

标签: c++ templates inner-classes friend-function

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

首先,当然会编译以下内容(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耦合;它的所有特殊成员(保存了析构函数和move ctor)都是私有的或已删除,Class1::Func是唯一实例化Class2的东西(并通过move ctor将其返回给{{1}的用户) }。因此,尽管不希望将整个Class1都与朋友相处,但还是会遇到一些困难。

谢谢。

2 个答案:

答案 0 :(得分:3)

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

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);那样T依赖于相同的模板参数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 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

答案 1 :(得分:2)

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

#ifdef _MSC_VER
    friend class Class1;
#else
    template <typename U>
    friend void Class1::Func(U& x);
#endif

添加。 Bug report