5

1 つのストリームではなく複数のストリームに<<出力できるストリーム オペレータを作成しようとしています。std::tuple基本的に、私はUnixteeコマンドをc ++で記述しようとしています。

std::tie(std::cout,std::clog) << 1;

c++11 で可変個引数テンプレート プログラミングを使用して、ストリーム演算子を再帰的に記述しようとしました。私がこれまでに持っているのは、以下のコードのとおりです。しかし、コードはコンパイルされず、エラー メッセージは非常に長くなります。

私の質問は、コードを修正して機能させる方法ですか?

g++ -std=c++11(gcc-4.8.1) でコンパイルしたときの最初のエラー メッセージは次のとおりです。

test.cpp:24:33: error: no match for 'operator<<' (operand types are 'std::tuple<std::basic_ostream<char, std::char_traits<char> >&, std::basic_ostream<char, std::char_traits<char> >&>' and 'int')
   std::tie(std::cout,std::cout) << 1;

PS SOを検索しましたが、複合ストリームオブジェクトの作成に関する投稿がいくつかあります。このコードには、stream と streambuf の多くの内部構造が含まれています。ここで私が求めているのは、同様のタスクを達成するための単純で素朴なソリューションです。

ありがとう


私のコード:

#include <iostream>
#include <tuple>

template<typename _Value, typename Head, typename ... Tail>
struct _tee_stream {
  static std::tuple<Head,Tail...>& _print(std::tuple<Head,Tail...>& _s, const _Value& _t) {
    return std::make_tuple(std::get<0>(_s) << _t ,_tee_stream<Tail...,_Value>::_print(_s,_t));
  }
};

template<typename _Value>
struct _tee_stream<_Value, std::tuple<>> {
  static std::tuple<>& _print(std::tuple<>& _s, const _Value& _t)  {
    return _s;
  }
};

template< typename _Value, typename... _TElements>
std::tuple<_TElements...>& operator<<(std::tuple<_TElements...>& _s, const _Value& _t) {
  return _tee_stream<_Value, std::tuple<_TElements...>>::_print(_s, _t);
};

int main() {
  std::tie(std::cout,std::cout) << 1; //no compile
  std::make_tuple(std::cout,std::cout) << 1; //no compile either
}

更新: 以下は、@KerrekSBのサンプルコードに基づいて私にとってうまくいったものです:

#include <iostream>
#include <tuple>
#include <utility>
#include <fstream>


template <unsigned int N>
struct tee_stream
{
  template <typename ...Args, typename T>
  static std::tuple<Args...> & print(std::tuple<Args...> & t, T && x)
  {
    std::get<sizeof...(Args) - N>(t) << x;
    tee_stream<N - 1>::print(t, std::forward<T>(x));
    return t;
  }
};

template <>
struct tee_stream<0>
{
  template <typename ...Args, typename T>
  static std::tuple<Args...> & print(std::tuple<Args...> &, T &&) {}
};

template <typename ...Args, typename T>
std::tuple<Args...> & operator<<(std::tuple<Args...> & t, T && x)
{
  return tee_stream<sizeof...(Args)>::print(t, std::forward<T>(x));
}

template <typename ...Args, typename T>
std::tuple<Args...> & operator<<(std::tuple<Args...> && t, T && x)
{
  return tee_stream<sizeof...(Args)>::print(t, std::forward<T>(x));
}

int main()
{
  std::ofstream os("a.txt");
  auto t = std::tie(std::cout, os);
  t << "Foo" << "Bar\n";
  std::tie(std::cout, os) << "Foo" << "Bar\n";
}

http://ideone.com/fBXuvP


@ジャロッド42、

どうもありがとう。あなたのコードは、私のプロトタイプよりもはるかにコンパクトに再帰/ループを実行し、私のコードでの参照型の使用を修正します。元のテスト ケースは、デモで示したとおりに機能します。ただし、以下の「not OK」行に示すように、ストリームで( std::endl「Foo」のstd::ofstream代わりに) または (の代わりに)を使用すると、バージョンをコンパイルできません。std::coutそれらも修正する方法はありますか?

#include <iostream>
#include <fstream>
#include <tuple>

#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>

template <std::size_t...> struct index_sequence {};

template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};

#endif // make_index_sequence

namespace detail
{
  template <typename Tuple, typename T, std::size_t...Is>
  Tuple output(const Tuple& t, const T& x, index_sequence<Is...>) {
    return Tuple{(std::get<Is>(t) << x)...};
  }
}

template <typename ...Args, typename T>
std::tuple<Args&...> operator<<(const std::tuple<Args&...>& t, const T& x) {
  return detail::output(t, x, make_index_sequence<sizeof...(Args)>());
}

int main() {
  std::ofstream os("aa.txt");
  os << "Hi" << std::endl;

  std::tie(std::cout, std::cout) << "Foo" << "Bar"; //OK
  std::tie(std::cout, std::cout) << "Foo" << "Bar" << std::endl; //not OK on endl
  std::tie(std::cout, os) << 1 << "Foo" << "Bar"; //not OK on ofstream

  return 0;
}
4

2 に答える 2

1

以下を使用できます。

#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>

template <std::size_t...> struct index_sequence {};

template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};

#endif // make_index_sequence

// Helper. C++11 cannot use: auto f() { return foo(); }
// Usage: auto f() -> Return(foo())
#define Return(ret) decltype(ret) { return ret; }

namespace detail
{
    template <typename Tuple, typename T, std::size_t...Is>
    auto output(const Tuple& t, const T& x, index_sequence<Is...>) ->
    Return (std::tie(std::get<Is>(t) << x...))
}

template <typename ...Args, typename T>
auto operator<<(const std::tuple<Args&...>& t, const T& x) ->
Return(detail::output(t, x, make_index_sequence<sizeof...(Args)>()))

実際の例

于 2014-07-24T09:43:50.327 に答える
0

1 つの問題は、次の引数にありますstd::tuple<_TElements...>& _s。およびによって返される一時値
を使用しようとしているため、一時値を参照にバインドできないため、コンパイラ エラーが発生します。operator <<std::tiestd::make_tuple

ただし、 const 参照 ( std::tuple<_TElements...> const& _s) は機能します。
(右辺値参照も使用できます)

_また、アンダースコア ( )で始まる名前は使用しないでください。それらは実装のために予約されています。

于 2014-07-24T00:28:12.750 に答える