LoginSignup
2
2

More than 3 years have passed since last update.

Python の print を C++ でも (n 番煎じ)

Posted at

はじめに

Pythonみたいなprint関数をC++で書きたい!
上の記事に触発されて自分でも書いてみた話。

方針

  • operator<< が使える場合は優先して使う
  • Range, Set, Map, Tuple っぽいものが現れたらいい感じに表示する
  • Python の print らしくするために、キーワード引数 (sep, end, file, flush) を実装する

実装

operator<< が使えるかを知るために、今回はクラステンプレートと std::void_t による detection idiom を用いる。

template <class Stream, class T, class Void = void>
struct is_insertable : std::false_type {};

template <class Stream, class T>
struct is_insertable<Stream, T,
  std::void_t<decltype(std::declval<Stream>() << std::declval<T>())>
> : std::true_type {};

template <class Stream, class T>
constexpr bool is_insertable_v = is_insertable<Stream, T>::value;

static_assert(is_insertable_v<std::ostream &, int>);

Range などの検出も同様に行う。コンセプトがあれば楽なのかもしれない。

キーワード引数は、まあ愚直に実装する。予期せぬ代入を避けるため、名前の頭にアンダースコアをつけるのがよいと思われる (参考)。

できたもの

pyprint.hpp
C++17 必須。GCC 9.1.0、Clang 8.0.1、Visual C++ 14.2 でたぶん動いている。

// ... 標準ライブラリのインクルード ...

#include "./pyprint.hpp"

int main() {
  using namespace std;
  using namespace pyprint;

  // 基本
  print(42, 3.5, "Hello, world!");
  // 42 3.5 Hello, world!

  // Range
  print(vector<vector<string>>{{"foo"s, "bar"s,}, {}, {"baz"s, "qux"s}});
  // [[foo, bar], [], [baz, qux]]

  // Set と Map
  print(set{42, 23, 50}, unordered_map<string, int>{{"hoge"s, 15}, {"fuga"s, 21}});
  // {23, 42, 50} {fuga: 21, hoge: 15}

  // Tuple
  print(pair{'A', "bcd"sv}, tuple{list{1, 2}, set{'A', 'B'}});
  // (A, bcd) ([1, 2], {A, B})

  // キーワード引数
  print(42, L"Hello, error!", _file = wcerr, _sep = L'\n', _end = L"\n-- END --\n");
  // 42
  // Hello, error!
  // -- END --
}

Q&A

Q. {fmt} とかでよいのでは?
A. せやな

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2