Допустим, есть какие-то единообразные инструкции над несколькими переменными
if(x % 2 == 0) ++x;
if(y % 2 == 0) ++y;
if(z % 2 == 0) ++z;
Как такое делается в современном c++? Я попробовал range-based for, но заработал только вариант с указателями.
for(auto t: {&x, &y, &z})
if((*t) % 2 == 0) ++(*t);
Reference/dereference тут выглядит явно неуместно. Можно как-то по-другому?
Update
С помощью анонимусов получилось вот такое решение
#include <cstdio>
#include <initializer_list>
#include <functional>
#define rlist(x, ...) (std::initializer_list<std::reference_wrapper<decltype(x)>>({x, __VA_ARGS__}))
int main()
{
int x = 2, y = 3, z = 4;
for(auto t : rlist(x, y, z)) if(t % 2 == 0) ++t;
printf("%d %d %d\n", x, y, z);
return 0;
}
При использовнии выглядит достаточно прилично (а на макрос можно не смотреть). Требует стандарта C++11. Что с производительностью - пока не знаю.
Update 2
Решение на шаблонах от eao197
#include <iostream>
using namespace std;
template<typename F> void apply_to_all(F &&) {}
template<typename F, typename T, typename... O>
void apply_to_all(F && f, T && x, O && ...other) {
f(forward<T>(x));
apply_to_all(forward<F>(f), forward<O>(other)...);
}
int main() {
int x = 2, y = 3, z = 4, v = 5, w = 6;
apply_to_all([](int & v) { if(v % 2 == 0) ++v; },
x, y, z, v, w);
apply_to_all([](int v) { cout << v << " "; },
x, y, z, v, w);
cout << endl;
return 0;
}
auto
вместо int
в лямбде.В С++17 за счет if constexpr не нужно будет делать пустую заглушку для прекращения рекурсии вызовов:
template<typename F, typename T, typename... O>
void apply_to_all(F && f, T && x, O && ...other) {
f(forward<T>(x));
if constexpr(0 != sizeof...(other))
apply_to_all(forward<F>(f), forward<O>(other)...);
}