在下面的示例代码中,它显示可以从第一个模板参数隐式创建boost :: tuple。
因此,我无法编写<<
运算符,因为它变得模棱两可。
我也不明白为什么ostringstream& << float
也含糊不清。这没有任何隐含的结构。为什么这也会给出含糊不清的错误?
#include <iostream>
#include <boost/tuple/tuple.hpp>
#include <sstream>
#include <string>
using namespace std;
class Myclass
{
};
typedef boost::tuple<int,float,Myclass> Mytuple;
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
float f = tuple_.get<1>();
//os_ << (int)tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
//os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
int main()
{
Mytuple t1;
t1 = 3; // Working because int is implicitly converted into Mytuple!! WHY?
//t1 = 3.0f; // Error because no matching constructor. Fine.
return 0;
}
错误Mesasge:
tupleTest2.C:18:错误:ISO C ++说这些都是模棱两可的 虽然第一次转化的最差转化率要好于最差转化率 转换为第二个:
答案 0 :(得分:4)
问题不在于元组,而在于您的运营商。这很好用:
ostream& operator<<(ostream& os_, Mytuple tuple_)
{
os_ << tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
问题是ostringstream从ostream继承operator<<
,它具有此签名:ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
是允许的。那么
ostream& operator<<(ostream& os, T t)
(使用c ++中的所有可用类型更改T,请参阅operator<< reference page
修改强>
这是一个简化的例子(没有元组):
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
const int i = tuple_.get<0>();
os_ << i; // error in this line
return os_;
}
现在错误:
dfg.cpp: In function ‘std::ostringstream& operator<<(std::ostringstream&, Mytuple)’:
dfg.cpp:18: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/ostream.tcc:111: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
dfg.cpp:14: note: candidate 2: std::ostringstream& operator<<(std::ostringstream&, Mytuple)
以上错误消息说:无法在两个运算符operator<<(ostream&,...)
和operator<<(ostringstream&,...). This also raises another question : why on earth do you need
运算符&lt;&lt;(ostringstream&amp;,...)`之间进行选择?
答案 1 :(得分:3)
写作时
os << tuple_.get<0>();
没有匹配这两个参数的函数。相反,编译器可以选择对任一参数
应用隐式转换std::ostream << int
或
std::ostringstream << MyTuple
后者将发生在boost::tuple
构造函数中,该构造函数可以获取任意数量的参数,直到元组元素的数量。 (并且float
失败,因为float
可以转换为int
。)
重载流运算符时,请使用基类作为左侧(ostream
甚至basic_ostream<CharT, Traits>
。
修改:您可以通过转换第一个参数来消除歧义歧义。
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
static_cast<std::ostream&>(os_) << tuple_.get<0>();
static_cast<std::ostream&>(os_) << tuple_.get<1>();
static_cast<std::ostream&>(os_) << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
然而,使用ostringstream
重载运算符仍然是一个坏主意,因为它不适用于运算符链接。
MyTuple a, b;
ostringstream ss;
ss << a << ' ' << b;
将调用:
1)ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
2)ostream& ostream::operator<<(char)
3) ostream& operator<<(ostream&&, boost::tuple<int,float,Myclass>
答案 2 :(得分:1)
所有告诉您使用::std::ostream
代替::std::ostringstream
的人都是绝对正确的。你不应该那样使用::std::ostringstream
。
但我对你的代码的主要负担是令人痛苦的缺乏普遍性。它只适用于一种特定的元组类型,而不是全部类型。
所以我在C ++ 0x中为operator <<
写了一个::std::tuple
,它适用于任何使用operator <<
单独编写成员的元组。使用Boost的元组类型可以相对容易地翻译它。这是:
template < ::std::size_t fnum, typename tup_type>
void print_fields(::std::ostream &os, const tup_type &val)
{
if (fnum < ::std::tuple_size<tup_type>::value) {
::std::cerr << "Fred " << fnum << '\n';
os << ::std::get<fnum, tup_type>(val);
if (::std::tuple_size<tup_type>::value > (fnum + 1)) {
os << ", ";
}
print_fields<fnum + 1, tup_type>(os, val);
}
}
template < ::std::size_t fnum, typename... Elements>
class field_printer;
template <typename... Elements>
class field_printer<0, Elements...> {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
}
};
template < ::std::size_t fnum, typename... Elements>
class field_printer {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
constexpr auto tupsize = ::std::tuple_size<tup_type>::value;
os << ::std::get<tupsize - fnum, Elements...>(val);
if (fnum > 1) {
os << ", ";
}
field_printer<fnum - 1, Elements...>::print_field(os, val);
}
};
template <class... Types>
::std::ostream &operator <<(::std::ostream &os, const ::std::tuple<Types...> &val)
{
typedef ::std::tuple<Types...> tup_type;
os << '(';
field_printer< ::std::tuple_size<tup_type>::value, Types...>::print_field(os, val);
return os << ')';
}
这会将元组打印为"(element1, element2, ...elementx)"
。