首页 文章

是否有合法的方法使用operator <<打印元组和对?

提问于
浏览
7

我有一组模板/函数允许我打印一个元组/对,假设元组/对中的每个类型都为它定义了 operator<< . 不幸的是,由于17.4.3.1,将 operator<< 重载添加到 std 是违法的 . 有没有其他方法让ADL找到我的 operator<< ?如果没有,在 namespace std{} 包裹我的过载是否有任何实际伤害?

感兴趣的人的代码:(我正在使用gcc-4.5)

namespace tuples {
  using ::std::tuple;
  using ::std::make_tuple;
  using ::std::get; 
namespace detail {

template< typename...args >
size_t size( tuple<args...> const& )
{
  return sizeof...(args);
};

template<size_t N>
struct for_each_ri_impl
{
  template<typename Func, typename Tuple>
  void operator()(Func func, Tuple const& arg)
  {
    for_each_ri_impl<N-1>()(func, arg );
    func( get<N>( arg ), size(arg) - N - 1 );
  }
};

template<>
struct for_each_ri_impl<0>
{
  template<typename Func, typename Tuple>
  void operator()(Func func, Tuple const& arg)
  {
    func( get<0>( arg ), size(arg) - 1 );
  }
};
}//detail

template<typename Func, typename ... Args>
void for_each_ri( tuple<Args...>const& tup, Func func )
{
  detail::for_each_ri_impl< sizeof...(Args)-1>()( func, tup );
}


struct printer {
  std::ostream& out;
  const std::string& str;
  explicit printer( std::ostream& out=std::cout, std::string const& str="," ) : out(out), str(str) { }

  template<typename T>void operator()(T const&t, size_t i=-1) const { out<<t; if(i) out<<str; }
};

//Should this next line go into namespace std? Is there another way?
template<typename ... Args>
std::ostream& operator<<(std::ostream& out, std::tuple< Args... > const& tup)
{
  out << '[';
  tuples::for_each_ri( tup, tuples::printer(out,", ") );
  return out << ']';
}

} //tuples

//Edits --
int main()
{
using namespace std;

cout<<make_tuple(1,'a',"Hello")<<endl;

return 0;
}

编制以上产量:

test.cpp:在函数'int main()'中:test.cpp:69:31:错误:无法将'std :: ostream'左值绑定到'std :: basic_ostream &&'> / opt / local / include / gcc45 / c / ostream:579:5:错误:初始化'std :: basic_ostream <_CharT,_Traits>&std :: operator <<的参数1(std :: basic_ostream <_CharT,_Traits> &&,const _Tp&)[with _CharT = char,_Traits = std :: char_traits,_Tp = std :: tuple]'

2 回答

  • 2

    在它周围放置自己的光包装类,然后重载operator <<以使用它 . 但请注意,即使您的光包装器具有隐式构造函数,您仍可能需要在将其传递给operator <<时显式使用它 .

    template< typename ...VA_ARGS >
        struct format_tuple
        {
           typedef tuple<VA_ARGS...> tuple_type;
        // any format variables
           const tuple_type & tup;
           format_tuple( const tuple_type& t): tup(t) {}
        };
    
        template< typename ...VA_ARGS > format_tuple<VA_ARGS...> makeFormatTuple( const tuple<VA_ARGS...> & t ) 
        {
           return format_tuple( t );
        }
    
        template<typename ...VA_ARGS>
        std::ostream& operator<<( std::ostream& os, const format_tuple<VA_ARGS...> & ft ) 
        {
          // original implementation
        }
    

    这是一个大纲,因为我不确定如何使用可变参数模板来完成它,尽管它应该是可能的 . 您可以使用1,2,3等参数轻松实现多个版本,例如:

    template<typename T1, typename T2, typename T3>
        class format_tuple_3; //etc
    
    
        template<typename T1, typename T2, typename T3>
        format_tuple_3<T1, T2, T3> makeFormatTuple( tuple<T1,T2,T3> const&); //etc
    
  • 2

    伤害是其他人(例如您想要使用的第三方库)也将这些声明添加到std . 即使他们的行为相同,你也会违反ODR .

    只需将它们放在项目的命名空间中:

    namespace kitsune_ymg {
    // Op<< overloads here.
    // Your "normal" stuff.
    void normal_stuff() {
      std::cout << std::pair<int, int>(42, 3);
    }
    

    然后项目中的任何内容都可以使用它们 .

    我仍然不确定为什么这对你不起作用,但似乎你想要这样的东西:

    namespace kitsune_ymg {
    namespace tuples {
      // Op<< overloads here.
    }
    using namespace tuples;
    // Your "normal" stuff.
    }
    
    namespace completely_separate_project {
    using kitsune_ymg::tuples;
    // Now you can use those op<< overloads in this scope, too.
    void perfectly_normal_beast() {
      std::cout << std::pair<int, int>(42, 3);
    }
    }
    

相关问题