homer512 icon

initializer_list FTW

homer512 | PRO | 05/09/16 03:12:59 PM UTC | 0 ⭐ | 768 👁️ | Never ⏰ | []
C++ |

2.38 KB

|

None

|

0 👍

/

0 👎

#include <algorithm>
// using std::find
#include <initializer_list>
// using std::initializer_list
#include <cstdarg>
// using std::va_list, va_start, va_end
 
 
/* Some dummy code for use in the examples */
struct Foo
{
  int x;
  bool operator==(const Foo& o) const
  { return x == o.x; }
};
 
void bar(const Foo&);
 
/* Code smell no 1: Multiple copy-and-paste function calls */
void original_1()
{
  Foo a, b, c;
  bar(a);
  bar(b);
  bar(c);
}
 
/* Solution: Use a range-based loop with an initializer_list */
void refactored_1()
{
  Foo a, b, c;
  for(const Foo* i: {&a, &b, &c})
    bar(*i);
}
 
/* Code smell no 2: variable argument lists in the 21st century
 *
 * Before anyone complains; yes there are still valid reasons for using them,
 * however, here we have better alternatives
 */
Foo original_2(Foo searched, Foo def, int n, ...)
{
  std::va_list ap;
  va_start(ap, n);
  for(int i = 0; i < n; ++i) {
    Foo cur = va_arg(ap, Foo);
    if(cur == searched) {
      va_end(ap);
      return cur;
    }
  }
  va_end(ap);
  return def;
}
 
/* Solution: initializer_list for arguments
 *
 * Obviously, this only works because we expect just a single type.
 * Replacing printf-style functions is still a challenge
 */
Foo refactored_2(Foo searched, Foo def, const std::initializer_list<Foo>& lst)
{
  std::initializer_list<Foo>::iterator found =
    std::find(lst.begin(), lst.end(), searched);
  return found == lst.end() ? def : *found;
}
 
/* Alternative solution: Pass iterators
 *
 * This is arguably more idiomatic, universal, and also works with obsolete
 * compilers.
 * On the other hand, it requires at least one more line of code to call it.
 * It still profits from initializer_lists, as demonstrated below
 */
template<class Iterator>
Foo alternative_2(Foo searched, Foo def, Iterator first, Iterator last)
{
  Iterator found = std::find(first, last, searched);
  return found == last ? def : *found;
}
 
/* Demonstrates the usage of the various solutions for smell no. 2 */
void call_2()
{
  Foo a, b, c, d, e;
  Foo f = original_2(a, b, 3, c, d, e);
  Foo g = refactored_2(a, b, {c, d, e});
  const auto& lst = {c, d, e};
  Foo h = alternative_2(a, b, lst.begin(), lst.end());
  /* for completeness: alternative_2 with C++03 */
  const Foo arr[] = {c, d, e};
  Foo i = alternative_2(a, b, arr, arr + sizeof(arr)/ sizeof(*arr));
}

Comments