fork download
  1. #include <cstdio>
  2. #include <iostream>
  3. #include <string>
  4. #include <type_traits>
  5. #include <sstream>
  6. #include <functional>
  7. namespace safe
  8. {
  9. namespace detail
  10. {
  11. // No default. Everything should either be a basic_string or a
  12. // scalar. If something else gets by, this will fail to compile here
  13. template<typename T, typename Enable = void>
  14. struct remove_string;
  15.  
  16. // Handles scalars (primatives + pointers) by simply returning the input.
  17. // will be optimized out.
  18. template<typename T>
  19. struct remove_string<T, typename std::enable_if<std::is_scalar<T>::value>::type>
  20. {
  21. static T convert(T val)
  22. {
  23. return val;
  24. }
  25. };
  26.  
  27. // Handles basic strings by returning their c_str()
  28. template<typename Char, typename Traits>
  29. struct remove_string<std::basic_string<Char, Traits>, void>
  30. {
  31. typedef std::basic_string<Char, Traits> string_type;
  32. static auto convert(const string_type& val) -> decltype(val.c_str())
  33. {
  34. return val.c_str();
  35. }
  36. };
  37.  
  38. // Default, resort to stringstream to return a string for the value
  39. template<typename T, typename Enable = void>
  40. struct remove_object
  41. {
  42. static std::string convert(const T& val)
  43. {
  44. std::ostringstream s;
  45. s << val;
  46. return s.str();
  47. }
  48. };
  49.  
  50. // For primatives + pointers, just forward. Note, the decay used earlier
  51. // causes arrays to decay to pointers and use this.
  52. template<typename T>
  53. struct remove_object<T, typename std::enable_if<std::is_scalar<T>::value>::type>
  54. {
  55. static T convert(T val)
  56. {
  57. return val;
  58. }
  59. };
  60.  
  61. // For std::basic_string, just simply forward the reference, not copy is needed
  62. template<typename Char, typename Traits>
  63. struct remove_object<std::basic_string<Char, Traits>, void>
  64. {
  65. typedef std::basic_string<Char, Traits> string_type;
  66. static const string_type& convert(const string_type& val)
  67. {
  68. return val;
  69. }
  70. };
  71.  
  72. // For reference wrappers, unwrap the reference, and then decay it and return
  73. // whatever that would return.
  74. template<typename T>
  75. struct remove_object<std::reference_wrapper<T>, void >
  76. {
  77. typedef remove_object< typename std::decay<T>::type > sub_call;
  78. static auto convert(std::reference_wrapper<T> const& ref) -> decltype(sub_call::convert(ref.get()))
  79. {
  80. return sub_call::convert(ref.get());
  81. }
  82. };
  83.  
  84. template<typename ... Args>
  85. int printf(const char* fmt, const Args&... args)
  86. {
  87. //std::cout << __PRETTY_FUNCTION__ << std::endl;
  88. return std::printf(fmt, remove_string<typename std::decay<const Args&>::type >::convert(args)...);
  89. }
  90.  
  91. }
  92.  
  93. template<typename ... Args>
  94. int printf(const char* fmt, const Args&... args)
  95. {
  96. //std::cout << __PRETTY_FUNCTION__ << std::endl;
  97. return detail::printf(fmt, detail::remove_object<typename std::decay<const Args&>::type>::convert(args)...);
  98. }
  99.  
  100. template<typename ... Args>
  101. int printf(const std::string& fmt, const Args&... args)
  102. {
  103. return printf(fmt.c_str(), args...);
  104. }
  105.  
  106. }
  107.  
  108. struct X
  109. {
  110. int i;
  111. explicit X(int i) :
  112. i(i)
  113. {
  114. }
  115. };
  116.  
  117. std::ostream& operator <<(std::ostream& str, const X& x)
  118. {
  119. str << "X(" << x.i << ")";
  120. return str;
  121.  
  122. }
  123.  
  124.  
  125. int main()
  126. {
  127. const std::string h("Hello");
  128. char w[] = "World";
  129. const char* t = "There!";
  130. char* w2 = w;
  131. int i = 10;
  132. X x(456);
  133. using safe::printf;
  134.  
  135. printf("%s %s %s %s %d %s, %s %f\n", h, w, t, std::string("Temp"), i, x, "foo", 0.12345);
  136.  
  137. printf(std::string("%s %s %s\n"), "More fun!", x, w2);
  138.  
  139. printf("Ref Test: %s %s %s\n", std::ref(w), std::ref(h), std::cref(x));
  140. }
Success #stdin #stdout 0s 3432KB
stdin
Standard input is empty
stdout
Hello World There! Temp 10 X(456), foo 0.123450
More fun! X(456) World
Ref Test: World Hello X(456)