| 1 | #include "templ_literal.h"
|
|---|
| 2 | #include <cstddef>
|
|---|
| 3 | #include <stdio.h>
|
|---|
| 4 |
|
|---|
| 5 | template< class >
|
|---|
| 6 | struct FormatSupportedType;
|
|---|
| 7 |
|
|---|
| 8 | #define SUPPORTED_TYPE(C, T) \
|
|---|
| 9 | template<> struct FormatSupportedType< T > \
|
|---|
| 10 | { \
|
|---|
| 11 | constexpr static bool supports(char c) \
|
|---|
| 12 | { return ( c == C ); } \
|
|---|
| 13 | }
|
|---|
| 14 |
|
|---|
| 15 | SUPPORTED_TYPE('c', char);
|
|---|
| 16 | SUPPORTED_TYPE('d', int);
|
|---|
| 17 |
|
|---|
| 18 | template< std::size_t N >
|
|---|
| 19 | constexpr bool checkFormatHelper( const char (&format)[N], std::size_t current )
|
|---|
| 20 | {
|
|---|
| 21 | return
|
|---|
| 22 | current >= N ?
|
|---|
| 23 | true
|
|---|
| 24 | : format[current] != '%' ?
|
|---|
| 25 | checkFormatHelper( format, current + 1 )
|
|---|
| 26 | : format[current + 1] == '%' ?
|
|---|
| 27 | checkFormatHelper( format, current + 2 )
|
|---|
| 28 | :
|
|---|
| 29 | false;
|
|---|
| 30 | }
|
|---|
| 31 |
|
|---|
| 32 | template< std::size_t N, class T, class... Ts >
|
|---|
| 33 | constexpr bool checkFormatHelper( const char (&format)[N], std::size_t current, const T& arg, const Ts & ... args )
|
|---|
| 34 | {
|
|---|
| 35 | return
|
|---|
| 36 | current >= N ?
|
|---|
| 37 | false
|
|---|
| 38 | : format[current] != '%' ?
|
|---|
| 39 | checkFormatHelper( format, current + 1, arg, args... )
|
|---|
| 40 | : (format[current] == '%' && format[current + 1] == '%') ?
|
|---|
| 41 | checkFormatHelper( format, current + 2, arg, args... )
|
|---|
| 42 | : FormatSupportedType< T >::supports(format[current + 1]) &&
|
|---|
| 43 | checkFormatHelper( format, current + 2, args... );
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | template< std::size_t N, class... Ts >
|
|---|
| 47 | constexpr bool checkFormat( const char (&format)[N], const Ts & ... args )
|
|---|
| 48 | {
|
|---|
| 49 | return checkFormatHelper( format, 0, args... );
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | #define safe_printf_1(FORMAT, ...) \
|
|---|
| 53 | static_assert(checkFormat( FORMAT, __VA_ARGS__ ), "Format is incorrect"); \
|
|---|
| 54 | printf(FORMAT, __VA_ARGS__)
|
|---|
| 55 |
|
|---|
| 56 | template< char... FORMAT, class... ARGS >
|
|---|
| 57 | int safe_printf_2(TemplateLiteral<FORMAT...>, ARGS... args)
|
|---|
| 58 | {
|
|---|
| 59 | constexpr char format[] = {FORMAT... , '\0'};
|
|---|
| 60 | static_assert( checkFormat(format, args... ), "Format is incorrect");
|
|---|
| 61 | return printf( format, args... );
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | int main()
|
|---|
| 65 | {
|
|---|
| 66 | safe_printf_1("%c %d", 'x', 257);
|
|---|
| 67 | safe_printf_2(TEMPLATE_LITERAL("%c %d"), 'x', 257);
|
|---|
| 68 | }
|
|---|