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 | }
|
---|