重载"std::ostream"运算符时,是否有方法更改默认非类型模板参数


#include <iostream>
struct Foo {
template <int bias = 5>
void print() {
std::cout << bias << std::endl;
}
};
template <int bias = 5>
std::ostream &operator<<(std::ostream &os, const Foo &foo) {
return os << bias;
}
int main() {
Foo a;
a.print();
a.print<>();
a.print<1>();
std::cout << a << std::endl;
return 0;
}

通过显示这段代码,我的意思是,尽管实现很糟糕,但有没有办法将默认参数5更改为使用std::cout << a << std::endl格式输出Foo a,并保持struct不变?

是的,有一种方法可以显式调用运算符,这允许完整的模板实例化语法:

operator<<<3>(std::cout, a);

不过可读性不太好。为了恢复以前的行为(除了bias的值(,您可以添加一个额外的

std::cout << 'n';

或者继续使用链接,请参阅Werner Henze的答案。

当您像运算符一样调用operator <<时,不能添加模板参数。

std:cout << a << std::endl;

但是,如果像函数一样调用operator <<,则可以添加模板参数。请注意,由于返回类型为std::ostream &,您可以在运算符风格的语法中调用更多的operator <<

operator<< <3>(std::cout, a) << std::endl;

也可以在输出a之前添加更多的operator <<调用,但这一切看起来并不像原来的调用那么好。

operator<< <3>(std::cout << "a=", a) << std::endl;

另一个使用operator <<的原始链接的选项通过引入一个helper类来工作。

template<int Bias>
struct Biased {
Biased(Foo& foo) :_foo{ foo } {}
Foo& _foo;
};
template<int Bias>
std::ostream& operator<<(std::ostream& os, const Biased<Bias>& biased) {
return os << Bias;
}
std::cout << "a=" << Biased<42>(a) << std::endl;

请注意,我在Biased中添加了_foo,这样Biasedoperator <<也可以根据需要打印_foo的内容(这在这里的代码中不会发生(。

在这种情况下,我更喜欢提供一个很好的工具来明确意图。

template<int bias>
struct Prefer
{
Prefer(Foo& foo) :foo{foo} {}
std::ostream &print(std::ostream &os) const {
return operator<< <bias>(os, foo);
}
private:
Foo& foo;
};
template <int bias>
std::ostream &operator<<(std::ostream &os, const Prefer<bias> &pref) {
return pref.print(os);
}
int main() {
Foo a;
a.print();
a.print<>();
a.print<1>();
std::cout << Prefer<2>(a) << std::endl;
std::cout << Prefer<10>(a) << std::endl;
return 0;
}

https://godbolt.org/z/j49Eo9

最新更新