[英]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.这里有两件事在起作用。
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.查看拒绝的原因。
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演示
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;
}
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;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.