Advertisement
homer512

initializer_list FTW

May 9th, 2016
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.38 KB | None | 0 0
  1. #include <algorithm>
  2. // using std::find
  3. #include <initializer_list>
  4. // using std::initializer_list
  5. #include <cstdarg>
  6. // using std::va_list, va_start, va_end
  7.  
  8.  
  9. /* Some dummy code for use in the examples */
  10. struct Foo
  11. {
  12.   int x;
  13.   bool operator==(const Foo& o) const
  14.   { return x == o.x; }
  15. };
  16.  
  17. void bar(const Foo&);
  18.  
  19. /* Code smell no 1: Multiple copy-and-paste function calls */
  20. void original_1()
  21. {
  22.   Foo a, b, c;
  23.   bar(a);
  24.   bar(b);
  25.   bar(c);
  26. }
  27.  
  28. /* Solution: Use a range-based loop with an initializer_list */
  29. void refactored_1()
  30. {
  31.   Foo a, b, c;
  32.   for(const Foo* i: {&a, &b, &c})
  33.     bar(*i);
  34. }
  35.  
  36. /* Code smell no 2: variable argument lists in the 21st century
  37.  *
  38.  * Before anyone complains; yes there are still valid reasons for using them,
  39.  * however, here we have better alternatives
  40.  */
  41. Foo original_2(Foo searched, Foo def, int n, ...)
  42. {
  43.   std::va_list ap;
  44.   va_start(ap, n);
  45.   for(int i = 0; i < n; ++i) {
  46.     Foo cur = va_arg(ap, Foo);
  47.     if(cur == searched) {
  48.       va_end(ap);
  49.       return cur;
  50.     }
  51.   }
  52.   va_end(ap);
  53.   return def;
  54. }
  55.  
  56. /* Solution: initializer_list for arguments
  57.  *
  58.  * Obviously, this only works because we expect just a single type.
  59.  * Replacing printf-style functions is still a challenge
  60.  */
  61. Foo refactored_2(Foo searched, Foo def, const std::initializer_list<Foo>& lst)
  62. {
  63.   std::initializer_list<Foo>::iterator found =
  64.     std::find(lst.begin(), lst.end(), searched);
  65.   return found == lst.end() ? def : *found;
  66. }
  67.  
  68. /* Alternative solution: Pass iterators
  69.  *
  70.  * This is arguably more idiomatic, universal, and also works with obsolete
  71.  * compilers.
  72.  * On the other hand, it requires at least one more line of code to call it.
  73.  * It still profits from initializer_lists, as demonstrated below
  74.  */
  75. template<class Iterator>
  76. Foo alternative_2(Foo searched, Foo def, Iterator first, Iterator last)
  77. {
  78.   Iterator found = std::find(first, last, searched);
  79.   return found == last ? def : *found;
  80. }
  81.  
  82. /* Demonstrates the usage of the various solutions for smell no. 2 */
  83. void call_2()
  84. {
  85.   Foo a, b, c, d, e;
  86.   Foo f = original_2(a, b, 3, c, d, e);
  87.   Foo g = refactored_2(a, b, {c, d, e});
  88.   const auto& lst = {c, d, e};
  89.   Foo h = alternative_2(a, b, lst.begin(), lst.end());
  90.   /* for completeness: alternative_2 with C++03 */
  91.   const Foo arr[] = {c, d, e};
  92.   Foo i = alternative_2(a, b, arr, arr + sizeof(arr)/ sizeof(*arr));
  93. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement