考虑以下示例代码,将operator<<
重载为class A
:
#include <iostream>
class A {
template <typename T>
friend A &operator<<(A &a, const T &t)
{
std::cout << t << std::endl;
return a;
}
friend A &operator<<(A &a, const std::string &t)
{
return operator<<<std::string>(a, t + "x");
}
};
我的意图是第二个运算符显式调用第一个。
但是,在g ++ 7.4中,此操作失败
在函数'A&运算符<<(A&,const string&)'中:
错误:“ operator <<”未定义
返回运算符<<< std :: string>(a,t +“ x”);
^〜
错误:“>”令牌之前的预期主表达式
返回运算符<<< std :: string>(a,t +“ x”);
^
但是我不明白为什么不应该编译。
答案 0 :(得分:2)
班级好友功能不会暴露在任何范围内。朋友注入曾经是一回事(在发明ADL之前),但是现在除非使用ADL除非事先声明,否则现在无法调用它们。在这种情况下,一种解决方法是事先在类外部声明模板函数。
class A;
template <typename T>
A &operator<<(A &a, const T &t);
答案 1 :(得分:1)
调用函数而不是调用运算符。
#include <iostream>
class A {
template <typename T>
static A &print(A &a, const T &t)
{
std::cout << t << std::endl;
return a;
}
template <typename T>
friend A &operator<<(A &a, const T &t)
{
return print(a, t);
}
friend A &operator<<(A &a, const std::string &t)
{
return print(a, t + "x");
}
};
答案 2 :(得分:1)
您似乎希望specialize your template function,但您做得不太正确。它应该看起来像这样:
template <> friend A& operator<< <std::string>(A &a, const std::string &t)
{
// Print in here some how. It's not exactly clear to me how you intend to
// do this, as doing something like a << t will create infinite recursion
// finally, return a
return a;
}
您的另一个选择是切换功能的顺序,在创建第一个功能后创建模板功能
friend A &operator<<(A &a, const std::string &t)
{
// Again, still not sure what you want to do here
// I just want to stress again though, don't do something
// like a << t, or operator<<(a,t)
// That will crash hard and fast, as there is no way to resolve
// it. It will create infinite recursion
return a;
}
template <typename T>
friend A &operator<<(A &a, const T &t)
{
std::cout << t << std::endl;
return a;
}
我的意图是第二个运算符显式调用第一个。
因此,首先,在这种情况下,您实际上需要第一个选项。
第二,要执行此操作,您将需要为t
选择一种类型。您可以这样做:
operator<< <SomeType>(a,t);
请记住,t
必须是implicitly converted至SomeType
。否则,SomeType
需要通过调用其构造函数来创建:
operator<< <SomeType>(a,SomeType(/* parameters to construct a SomeType ... */));
注意:做类似operator<< <SomeType>(a,t + "x")
的事情将始终变成infinitely recursive,并最终崩溃。这是因为t + "x"
始终是std::string
。这意味着编译器将始终无限调用此函数的重载,直到最终从stack overflow崩溃为止。所以不要那样。