如何为 boost::tuple 编写一个 '<<' 运算符?



在下面的示例代码中,它表明可以从第一个模板参数隐式创建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++说这些是不明确的,甚至尽管第一个的最坏转换比最坏的要好第二次转换:

问题不在于元组,而在于运算符。这很好:

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,请参阅操作员<<参考页面

编辑

下面是一个简化的例子(没有元组(:

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;(ostringstream&,…(`?

当您编写时

 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>

所有那些告诉您使用::std::ostream而不是::std::ostringstream作为类型的人都是绝对正确的。你不应该那样使用::std::ostringstream

但我对您的代码的主要不满是缺乏通用性。它只适用于一种特定的元组类型,而不是所有的元组类型。

因此,我在C++0x中为::std::tuple编写了一个operator <<,适用于任何可以使用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)"

相关内容

  • 没有找到相关文章

最新更新