#include // using std::find #include // using std::initializer_list #include // 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& lst) { std::initializer_list::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 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)); }