SlideShare a Scribd company logo
1 of 21
Download to read offline
値をフォーマットして 
出力してますか
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

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

C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competitionyak1ex
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competitionyak1ex
 
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」Hiro H.
 
C++によるソート入門
C++によるソート入門C++によるソート入門
C++によるソート入門AimingStudy
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
 
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)Hiro H.
 
Learning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.GeomtryLearning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.GeomtryAkira Takahashi
 
Write good parser in perl
Write good parser in perlWrite good parser in perl
Write good parser in perlJiro Nishiguchi
 
プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集tecopark
 
プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集tecopark
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPAkira Takahashi
 
ぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんとぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんとYutaka Tsumori
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61TATSUYA HAYAMIZU
 
Boost.B-tree introduction
Boost.B-tree introductionBoost.B-tree introduction
Boost.B-tree introductionTakayuki Goto
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語るAkira Takahashi
 

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

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

More from digitalghost

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

More from digitalghost (9)

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

拡張可能で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の持つ書式指定子のほとんど ● コンテナとかに対するデフォルト実装