简体   繁体   English

class模板的朋友有问题

[英]Problems with friends of class template

I am trying to create some friends functions for my class template.我正在尝试为我的 class 模板创建一些朋友功能。 I know you have to declare them outside the class first but I am having some weird results.我知道您必须首先在 class 之外声明它们,但我得到了一些奇怪的结果。

... ...

template <typename T>
class Matrix;

template <typename T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& mtrx);
template <typename T>
std::istream& operator>>(std::istream& is, const Matrix<T>& mtrx);
template <typename T>
Matrix<T> operator*(const T& t, const Matrix<T>& mtrx);

template <typename T>
class Matrix
{
public:

    friend std::ostream&    operator<< <>(std::ostream&, const Matrix&);
    friend std::istream&    operator>> <>(std::istream&, const Matrix&);

    Matrix                  operator*(const T&) const;
    friend Matrix<T>        operator* <>(const T& t, const Matrix& mtrx);
};

... ...

The two stream operators work fine for me, but the multiplication operator has issues.两个 stream 运算符对我来说工作正常,但乘法运算符有问题。 For some reason the compiler (Visual Studio) seems to think I am trying to declare a data member and keeps throwing a bunch of errors.出于某种原因,编译器(Visual Studio)似乎认为我正在尝试声明一个数据成员并不断抛出一堆错误。 Like喜欢

C2460 uses Matrix which is being defined; 
C2433 friend not permitted on data declarations; 
c2473 looks like a function definition, but there is no parameter list.

As far as I can tell, the implementation is the same as for the stream operators which work.据我所知,实现与工作的 stream 运算符相同。 Also, if I rename operator* to something else, like foo, it works fine.此外,如果我将 operator* 重命名为其他名称,例如 foo,它可以正常工作。

Now, I don't actually need to make this function a friend, my definition just reverses order of arguments and calls the member function version.现在,我实际上不需要把这个 function 变成朋友,我的定义只是颠倒了 arguments 的顺序,并调用了成员 function 版本。 But I still want to know what is going on and what is wrong.但我仍然想知道发生了什么,出了什么问题。

There are two things at play here.这里有两件事在起作用。

First第一的

A C++ compiler is permitted (but not required.) to diagnose errors at the time the template is parsed when all of the instantiations of the template would produce that error. C++ 编译器被允许(但不是必需的)在模板被解析时诊断错误,而模板的所有实例都会产生该错误。

This means that since you've not instantiated class template Matrix , compilers are free to diagnose the error.这意味着由于您尚未实例化 class 模板Matrix ,编译器可以自由地诊断错误。 For example, the given program is rejected by msvc but accepted(compiled) by gcc and clang in C++20.例如,给定程序被 msvc 拒绝,但在 C++20 中被 gcc 和 clang 接受(编译)。 Demo .演示

So this is not msvc bug.所以这不是 msvc 错误。 For more detailed explanation of this, refer to Template class compiles with C++17 but not with C++20 if unused function can't be compiled .更详细的解释请参考Template class compiles with C++17 but not with C++20 if used function can't be compiled

Note also that if you do instantiate Matrix for some template argument say by writing Matrix<int> , then the program is also rejected by gcc.另请注意,如果您通过编写Matrix<int>为某些模板参数实例化Matrix ,则该程序也会被 gcc 拒绝。 Demo .演示 See reason why this is rejected.查看拒绝的原因。


Important重要的

The important thing to note here is that the exact same program is rejected by all compilers with C++17 irrespective of whether you instantiate Matrix for a given template argument or not.这里要注意的重要一点是,无论您是否为给定的模板参数实例化Matrix ,所有带有 C++17 的编译器都会拒绝完全相同的程序。 Demo演示


Second第二

Now, lets see the reason for the program being rejected with all compilers in C++17.现在,让我们看看 C++17 中所有编译器拒绝程序的原因。

In your given program when you try to befriend a specialization of the function template operator* , the compiler starts lookup(looking up) for an operator* and it finds the non-template overloaded version and so stops looking further .在您给定的程序中,当您尝试与 function 模板operator*的特化成为朋友时,编译器开始查找(查找) operator*并找到非模板重载版本,因此停止进一步查找 Now, since it found a nontemplate version which cannot be specialized, it gives the error in all compilers.现在,由于它找到了一个无法专门化的非模板版本,它在所有编译器中都给出了错误

Lets, look at a contrived example:让我们看一个人为的例子:

template<typename T> void f(T){

}
template <typename T>
class Matrix
{
public:


    int                  f(const T&) const; //#1
    friend void          f<>(const Matrix& mtrx); //lookup find #1 and stops looking and so gives error
    
};;

int main()
{
    Matrix<int> m;
}

To solve the above error, it we've to reorder the declarations so that the lookup for operator* isn't found when befriending the specialization.为了解决上述错误,我们必须重新排序声明,以便在与专业化成为朋友时找不到operator*的查找。

This means we have to change the above program to:这意味着我们必须将上述程序更改为:

template<typename T> void f(T){ //#2

}
template <typename T>
class Matrix
{
public:


    
    friend void          f<>(const Matrix& mtrx); //lookup find #2  
    int                  f(const T&) const; //OK now
};;

int main()
{
    Matrix<int> m;
}

Summary概括

To solve the error you're getting you've to reorder the declarations for operator* like shown below:要解决您遇到的错误,您必须重新排序operator*的声明,如下所示:

template <typename T>
class Matrix
{
public:

    friend std::ostream&    operator<< <>(std::ostream&, const Matrix&);
    friend std::istream&    operator>> <>(std::istream&, const Matrix&);

    //reordered 
    friend Matrix<T>        operator* <>(const T& t, const Matrix& mtrx);
    Matrix                  operator*(const T&) const;
};

Demo演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM