我有一个非常简单的内联辅助类叫IpAddress
,它有2个运算符重载<<将对象序列化为一组自定义二进制流(运算符作为模板函数)或将其输出到std :: ostream(非模板运算符函数)。
#include <cstdint>
#include <string>
#include <array>
#include <iostream>
#include <sstream>
typedef uint8_t byte;
class IpAddress: public std::array<byte,4>
{
// ...
template<class S>
inline friend S& operator<<(S& left, const IpAddress& right) {
left.setBytes(right.data(), 4);
return left;
}
inline friend std::ostream& operator<< (std::ostream& left, const IpAddress& right) {
// do stuff eligible for an ostream
return left;
}
inline operator std::string() {
std::stringstream stream;
stream << *this;
return stream.str();
}
}
如您所见,还有一个运算符将地址转换为字符串。不幸的是,&lt;&lt;内部调用是选择错误的运算符&lt;&lt; (模板一),导致编译错误:
error: C2039: 'setBytes' : is not a member of 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>'
为什么编译器(在这种情况下为MSVC)使用非工作体选择错误的重载?为什么不更专业&#34; std :: ostream运算符?我该如何改变这种行为?谢谢!
答案 0 :(得分:0)
您没有发布完整的可编辑示例,因此我看不到呼叫网站。
然而,问题很可能是因为您流出的内容不是完全 ostream
。它可能来自ostream
。在这种情况下,template T
将是更好的匹配。
编辑:
除了样式评论(他们是对的,你会很好听),这是一个修复:
#include <iostream>
#include <utility>
#include <cstdint>
#include <array>
#include <sstream>
template<class T> static constexpr bool IsAnOstream = std::is_base_of<std::decay_t<T>, std::ostream>::value;
using byte = std::uint8_t;
struct IpAddress: public std::array<byte,4>
{
// ...
template<class S, std::enable_if_t<not IsAnOstream<S>>* = nullptr>
friend S& operator<<(S& left, const IpAddress& right) {
left.setBytes(right.data(), 4);
return left;
}
friend std::ostream& operator<< (std::ostream& left, const IpAddress& right) {
// do stuff eligible for an ostream
return left;
}
/*
* this is a bad idea - it can lead to all kinds of confusion
*
inline operator std::string() {
std::stringstream stream;
stream << *this;
return stream.str();
}
*/
};
// this is better - it's less surprising.
std::string to_string(const IpAddress& r)
{
std::stringstream stream;
stream << *this;
return stream.str();
}
struct MyStream
{
void setBytes(const uint8_t* p, size_t len) {}
};
int main()
{
IpAddress a;
MyStream s;
std::cout << a;
s << a;
return 0;
}