C++ 朋友模板操作符

C++ 朋友模板操作符,c++,visual-studio,templates,operator-overloading,friend-function,C++,Visual Studio,Templates,Operator Overloading,Friend Function,以下程序不在MS Visual Studio 19中编译 #include <iostream> #include <string> template <typename T> class A; template <typename T> std::ostream &operator <<( std::ostream &, const A<T> & ); template <typenam

以下程序不在MS Visual Studio 19中编译

#include <iostream>
#include <string>

template <typename T>
class A;

template <typename T>
std::ostream &operator <<( std::ostream &, const A<T> & );

template <typename T>
class A
{
private:
    T x;

public:
    A( const T &x ) : x( x ) {}

    friend std::ostream &::operator <<( std::ostream &, const A<T> & );
};

template <typename T>
std::ostream &operator <<( std::ostream &os, const A<T> &a )
{
    return os << "a.x = " << a.x;
}

int main()
{
    std::cout << A<std::string>( "Hello" ) << '\n';
}
#包括
#包括
模板
甲级;
模板

std::ostream&operator您的程序有缺陷;然而,VisualStudio中确实存在一个(或两个)bug

首先,您的
friend
声明应拼写为
,以表明它是一个模板专门化,即friend:

friend std::ostream &::operator <<<>( std::ostream &, const A<T> & );
//                                ^~
顺便说一句,gcc提供了一个有用的提示来进行此更改


但MSVC仍将错误地拒绝该计划;这似乎只发生在特定
运算符的模板上,您不需要声明
operator@TedLyngmo据我所知,类的每一个特化都有相应的算子的推导特化。看第二个编译的程序。@Vladfrommoskow这个美容效果好吗<代码>好友标准::ostream&::operator@HolyBlackCat ... 在-引用的段落似乎没有改变,因为。。。所以,没有发现任何线索。“泰德林莫不,它不是一个合格的ID。一个合格的ID看起来::操作员重读我在我的问题中提供的C++标准的引用。你所展示的是用C++ 20标准的其他引用描述的”(1.1)。如果朋友的名字是一个合格的或不合格的模板ID,朋友声明是指一个函数模板的专门化,否则,“@ VladfromMoscow,从我的链接的差异中删除标准列表后的C++ 20。”(03到20)以您期望的方式。因此,删除该列表是使标准与实现实践保持一致的问题。最后,您的代码被MSVC 19.22接受,被19.23拒绝。(根据godbolt)。因此,这也是最近的一个错误。
friend std::ostream &::operator <<<>( std::ostream &, const A<T> & );
//                                ^~
friend std::ostream &::operator <<<T>( std::ostream &, const A<T> & );
//                                ^~~
#include <iostream>
template<class> struct A;
template<class> struct B;
template<class T> std::ostream& f(std::ostream&, A<T>);
template<class T> std::ostream &operator<<(std::ostream&, A<T>);
template<class T> std::ostream& f(std::ostream&, B<T> const&);
template<class T> std::ostream &operator<<(std::ostream&, B<T> const&);
template<class T> struct A {
    friend std::ostream& ::f<T>(std::ostream&, A<T>);
    friend std::ostream& ::operator<<<T>(std::ostream&, A<T>);
};
template<class T> struct B {
    friend std::ostream& ::f<T>(std::ostream&, B<T> const&);
    friend std::ostream& ::operator<<<T>(std::ostream&, B<T> const&); // MSVC bug
};
template<class T> std::ostream& f(std::ostream& os, A<T>) { return os << "1"; }
template<class T> std::ostream& operator<<(std::ostream& os, A<T>) { return os << "2"; }
template<class T> std::ostream& f(std::ostream& os, B<T> const&) { return os << "3"; }
template<class T> std::ostream& operator<<(std::ostream& os, B<T> const&) { return os << "4"; }
int main() {
    f(std::cout, A<int>()) << ' ' << A<int>() << '\n';
    f(std::cout, B<int>()) << ' ' << B<int>() << '\n';
}