SlideShare a Scribd company logo
値をフォーマットして 
出力してますか
printf 
printf(“%3dn%3dn”, 42, 123); 
● 42 
123 
● 文字列の中に細かい出力制御を含めて書けるので割と便利 
● 組み込み型限定 
● フォーマット文字列と引数の整合性が取れてるか分からない 
(最近のコンパイラなら独自拡張で分かるかもしれない)
IOStream 
std::cout << std::setw(3) << 42 << 
'n' << 123 << 'n'; 
● ユーザ定義型でも組み込み型と同じように出力 
できるしフォーマットの細かい制御もできる 
● マニピュレータはクソ面倒
Boost.Format 
cout << boost::format(“%1%n%2%n”) % 
42 % 123); 
● ユーザ定義型に対しても使えるが細かいフォー 
マット制御は指定できない
拡張可能でprintfっぽい書式指定ができて書式 
指定文字列と引数をコンパイル時に検証できる文 
字列フォーマット関数を作った 
2014/09/20 
Boost.勉強会#16 大阪 
https://twitter.com/decimalbloat
拡張可能でprintfっぽい書式指定ができて書式 
指定文字列と引数をコンパイル時に検証できる文 
字列フォーマット関数を作ってる 
2014/09/20 
Boost.勉強会#16 大阪 
https://twitter.com/decimalbloat
細かいところの実装が間に合ってない
Desalt.Format 
● http://github.com/dechimal/desalt 
● printfっぽく書式を指定できて 
● ユーザ定義型に使えて 
● 書式指定文字列をコンパイル時に検証できる
すごい!
使い方 
DESALT_FORMAT_PRINT(“%3dn%3d”, 42, 123) 
● printfとだいたい同じ 
● 最初の引数にはコンパイル時に評価される文字列のみ使える 
● デフォルトでは組み込みの数値型と 
basic_ostream<CharT, Traits> ost について ost 
<< x; が定義されている型に対して使える 
– ただし浮動小数点数型は現在未実装 
– あとなんか忘れてるものもあるかもしれない
コンパイル時にエラーを検出 
DESALT_FORMAT_PRINT(“%d%”, 42); 
● 42% のつもり 
● static_assertで失敗する
ユーザ定義型に対して拡張する 
DESALT_FORMAT_PRINT(“%hoge %d”, 
my_int{42}, 123); 
● my_intはhoge指定子で2倍の値を出力すると 
する
こんな感じで作る 
struct my_int { int a; }; 
namespace desalt { namespace format { namespace traits { 
template<char const * String, std::size_t I, std::size_t E> 
struct argument_formatter<String, I, E, my_int> { 
static_assert(E - I >= 4, ""); 
static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); 
static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); 
static constexpr std::size_t end_pos = I + 4; 
static constexpr std::size_t used_indexes_count = 0; 
template<typename ...Args> 
static void format(std::ostream & ost, my_int i, Args const & ...) { 
ost << i.a * 2; 
} 
}; 
}}} 
● String は書式文字列,I はString中の my_int の書式の開始位置, E は長さ
こんな感じで作る 
struct my_int { int a; }; 
namespace desalt { namespace format { namespace traits { 
template<char const * String, std::size_t I, std::size_t E> 
struct argument_formatter<String, I, E, my_int> { 
static_assert(E - I >= 4, ""); 
static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); 
static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); 
static constexpr std::size_t end_pos = I + 4; 
static constexpr std::size_t used_indexes_count = 0; 
template<typename ...Args> 
static void format(std::ostream & ost, my_int i, Args const & ...) { 
ost << i.a * 2; 
} 
}; 
}}} 
● end_pos は my_int の書式指定子の終端の位置
こんな感じで作る 
struct my_int { int a; }; 
namespace desalt { namespace format { namespace traits { 
template<char const * String, std::size_t I, std::size_t E> 
struct argument_formatter<String, I, E, my_int> { 
static_assert(E - I >= 4, ""); 
static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); 
static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); 
static constexpr std::size_t end_pos = I + 4; 
static constexpr std::size_t used_indexes_count = 0; 
template<typename ...Args> 
static void format(std::ostream & ost, my_int i, Args const & ...) { 
ost << i.a * 2; 
} 
}; 
}}} 
● used_indexes_count はこのformatが消費した引数の数(詳細は後述)
こんな感じで作る 
struct my_int { int a; }; 
namespace desalt { namespace format { namespace traits { 
template<char const * String, std::size_t I, std::size_t E> 
struct argument_formatter<String, I, E, my_int> { 
static_assert(E - I >= 4, ""); 
static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); 
static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); 
static constexpr std::size_t end_pos = I + 4; 
static constexpr std::size_t used_indexes_count = 0; 
template<typename ...Args> 
static void format(std::ostream & ost, my_int i, Args const & ...) { 
ost << i.a * 2; 
} 
}; 
}}} 
● format は実際の処理を行う関数
こんな感じで作る 
struct my_int { int a; }; 
namespace desalt { namespace format { namespace traits { 
template<char const * String, std::size_t I, std::size_t E> 
struct argument_formatter<String, I, E, my_int> { 
static_assert(E - I >= 4, ""); 
static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); 
static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); 
static constexpr std::size_t end_pos = I + 4; 
static constexpr std::size_t used_indexes_count = 0; 
template<typename ...Args> 
static void format(std::ostream & ost, my_int i, Args const & ...) { 
ost << i.a * 2; 
} 
}; 
}}} 
● ost は出力先,i は出力する値,Args ... は引数リスト全体(詳細は後述)
ややこしい機能 
printf(“%2$d, %1$d”, 42, 123) 
● 123, 42 
● 位置指定 
● 特に何もしなくてもできる
ややこしい機能 
printf(“%0*d %d”, 42, 3, 123) 
● 042 123 
● 表示したい引数以外に使いたい引数がある 
● used_indexes_countに使った数を指定する 
● format関数に渡された引数リストから拾って 
くる
予定 
● printfの持つ書式指定子のほとんど 
● コンテナとかに対するデフォルト実装
終わり

More Related Content

PDF
お前は PHP の歴史的な理由の数を覚えているのか
PDF
C++11概要 ライブラリ編
ODP
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
PPTX
PDF
templateとautoの型推論
PDF
C++ Template Metaprogramming
PDF
2018年度 若手技術者向け講座 リファクタリング
PDF
Essential Scala 第5章 シーケンス処理
お前は PHP の歴史的な理由の数を覚えているのか
C++11概要 ライブラリ編
C++でのゲームプログラミングをしたときのお話 札幌C++勉強会 #4 〜スタートゲームプログラミング〜
templateとautoの型推論
C++ Template Metaprogramming
2018年度 若手技術者向け講座 リファクタリング
Essential Scala 第5章 シーケンス処理

Similar to 拡張可能でprintfっぽい書式指定ができて書式指定文字列と引数をコンパイル時に検証できる文字列フォーマット関数を作った (20)

PPT
C++0x in programming competition
PDF
C++0x in programming competition
PDF
Boost tour 1_44_0
PDF
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
PDF
Pfi Seminar 2010 1 7
PDF
C++によるソート入門
PDF
Python standard 2022 Spring
PDF
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
PDF
Learning Template Library Design using Boost.Geomtry
PDF
Write good parser in perl
PPT
プログラミングで言いたい聞きたいこと集
PPT
プログラミングで言いたいこと聞きたいこと集
PDF
ゲーム開発者のための C++11/C++14
PDF
Replace Output Iterator and Extend Range JP
PDF
ぼくのかんがえたさいきょうのついったーくらいあんと
PDF
わんくま同盟大阪勉強会#61
PDF
Boost.B-tree introduction
PDF
C++0x 言語の未来を語る
PPTX
C++0x総復習
C++0x in programming competition
C++0x in programming competition
Boost tour 1_44_0
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
Pfi Seminar 2010 1 7
C++によるソート入門
Python standard 2022 Spring
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
Learning Template Library Design using Boost.Geomtry
Write good parser in perl
プログラミングで言いたい聞きたいこと集
プログラミングで言いたいこと聞きたいこと集
ゲーム開発者のための C++11/C++14
Replace Output Iterator and Extend Range JP
ぼくのかんがえたさいきょうのついったーくらいあんと
わんくま同盟大阪勉強会#61
Boost.B-tree introduction
C++0x 言語の未来を語る
C++0x総復習
Ad

More from digitalghost (9)

PPTX
ナウなヤングにバカうけのイカしたタグ付き共用体
PDF
Define and expansion of cpp macro
PDF
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
PDF
君はまだ,本当のプリプロセスを知らない
PDF
C++コンパイラ GCCとClangからのメッセージをお読みください
PDF
No skk, no life.
PDF
Boost.Preprocessorでプログラミングしましょう
PDF
テンプレートメタプログラミング as 式
PDF
Preprocess-time Lambda Expression
ナウなヤングにバカうけのイカしたタグ付き共用体
Define and expansion of cpp macro
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
君はまだ,本当のプリプロセスを知らない
C++コンパイラ GCCとClangからのメッセージをお読みください
No skk, no life.
Boost.Preprocessorでプログラミングしましょう
テンプレートメタプログラミング as 式
Preprocess-time Lambda Expression
Ad

拡張可能でprintfっぽい書式指定ができて書式指定文字列と引数をコンパイル時に検証できる文字列フォーマット関数を作った

  • 2. printf printf(“%3dn%3dn”, 42, 123); ● 42 123 ● 文字列の中に細かい出力制御を含めて書けるので割と便利 ● 組み込み型限定 ● フォーマット文字列と引数の整合性が取れてるか分からない (最近のコンパイラなら独自拡張で分かるかもしれない)
  • 3. IOStream std::cout << std::setw(3) << 42 << 'n' << 123 << 'n'; ● ユーザ定義型でも組み込み型と同じように出力 できるしフォーマットの細かい制御もできる ● マニピュレータはクソ面倒
  • 4. Boost.Format cout << boost::format(“%1%n%2%n”) % 42 % 123); ● ユーザ定義型に対しても使えるが細かいフォー マット制御は指定できない
  • 8. Desalt.Format ● http://github.com/dechimal/desalt ● printfっぽく書式を指定できて ● ユーザ定義型に使えて ● 書式指定文字列をコンパイル時に検証できる
  • 10. 使い方 DESALT_FORMAT_PRINT(“%3dn%3d”, 42, 123) ● printfとだいたい同じ ● 最初の引数にはコンパイル時に評価される文字列のみ使える ● デフォルトでは組み込みの数値型と basic_ostream<CharT, Traits> ost について ost << x; が定義されている型に対して使える – ただし浮動小数点数型は現在未実装 – あとなんか忘れてるものもあるかもしれない
  • 11. コンパイル時にエラーを検出 DESALT_FORMAT_PRINT(“%d%”, 42); ● 42% のつもり ● static_assertで失敗する
  • 12. ユーザ定義型に対して拡張する DESALT_FORMAT_PRINT(“%hoge %d”, my_int{42}, 123); ● my_intはhoge指定子で2倍の値を出力すると する
  • 13. こんな感じで作る struct my_int { int a; }; namespace desalt { namespace format { namespace traits { template<char const * String, std::size_t I, std::size_t E> struct argument_formatter<String, I, E, my_int> { static_assert(E - I >= 4, ""); static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); static constexpr std::size_t end_pos = I + 4; static constexpr std::size_t used_indexes_count = 0; template<typename ...Args> static void format(std::ostream & ost, my_int i, Args const & ...) { ost << i.a * 2; } }; }}} ● String は書式文字列,I はString中の my_int の書式の開始位置, E は長さ
  • 14. こんな感じで作る struct my_int { int a; }; namespace desalt { namespace format { namespace traits { template<char const * String, std::size_t I, std::size_t E> struct argument_formatter<String, I, E, my_int> { static_assert(E - I >= 4, ""); static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); static constexpr std::size_t end_pos = I + 4; static constexpr std::size_t used_indexes_count = 0; template<typename ...Args> static void format(std::ostream & ost, my_int i, Args const & ...) { ost << i.a * 2; } }; }}} ● end_pos は my_int の書式指定子の終端の位置
  • 15. こんな感じで作る struct my_int { int a; }; namespace desalt { namespace format { namespace traits { template<char const * String, std::size_t I, std::size_t E> struct argument_formatter<String, I, E, my_int> { static_assert(E - I >= 4, ""); static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); static constexpr std::size_t end_pos = I + 4; static constexpr std::size_t used_indexes_count = 0; template<typename ...Args> static void format(std::ostream & ost, my_int i, Args const & ...) { ost << i.a * 2; } }; }}} ● used_indexes_count はこのformatが消費した引数の数(詳細は後述)
  • 16. こんな感じで作る struct my_int { int a; }; namespace desalt { namespace format { namespace traits { template<char const * String, std::size_t I, std::size_t E> struct argument_formatter<String, I, E, my_int> { static_assert(E - I >= 4, ""); static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); static constexpr std::size_t end_pos = I + 4; static constexpr std::size_t used_indexes_count = 0; template<typename ...Args> static void format(std::ostream & ost, my_int i, Args const & ...) { ost << i.a * 2; } }; }}} ● format は実際の処理を行う関数
  • 17. こんな感じで作る struct my_int { int a; }; namespace desalt { namespace format { namespace traits { template<char const * String, std::size_t I, std::size_t E> struct argument_formatter<String, I, E, my_int> { static_assert(E - I >= 4, ""); static_assert(*(String + I + 0) == 'h' && *(String + I + 1) == 'o', ""); static_assert(*(String + I + 2) == 'g' && *(String + I + 3) == 'e', ""); static constexpr std::size_t end_pos = I + 4; static constexpr std::size_t used_indexes_count = 0; template<typename ...Args> static void format(std::ostream & ost, my_int i, Args const & ...) { ost << i.a * 2; } }; }}} ● ost は出力先,i は出力する値,Args ... は引数リスト全体(詳細は後述)
  • 18. ややこしい機能 printf(“%2$d, %1$d”, 42, 123) ● 123, 42 ● 位置指定 ● 特に何もしなくてもできる
  • 19. ややこしい機能 printf(“%0*d %d”, 42, 3, 123) ● 042 123 ● 表示したい引数以外に使いたい引数がある ● used_indexes_countに使った数を指定する ● format関数に渡された引数リストから拾って くる
  • 20. 予定 ● printfの持つ書式指定子のほとんど ● コンテナとかに対するデフォルト実装