Допустим, у меня есть это:
struct HoldStuff {
std::vector<StuffItem> items;
std::set<StuffItem, StuffItemComparator> sorted_items;
}
Теперь, во время рефакторинга, у меня могут быть вещи в items
или я могу иметь это в sorted_items
, но независимо от того, что я хочу сделать то же самое с каждым элементом. Я хочу сделать что-то вроде этого:
HoldStuff holder; // assume it was filled earlier
auto iter = holder.items.empty() ? holder.sorted_items.begin() :
holder.items.begin();
auto iter_end = holder.items.empty() ? holder.sorted_items.end() :
holder.items.end();
for (; iter != iter_end; ++iter) {
auto& item = *iter;
// Do stuff
}
Когда я собираюсь скомпилировать это, я получаю сообщения об ошибках несовместимых типов операндов. Конечно, это возможно, нет?
У вас есть два варианта:
any_range
или же any_iterator
)do_stuff
в шаблон функции, который принимает любой вид итератора Вот иллюстрация с кодом:
#include <vector>
#include <set>
#include <iostream>
#include <boost/range/any_range.hpp>
template<typename Iterator>
void do_stuff(Iterator begin, Iterator end) {}
int main()
{
std::vector<int> items;
std::set<int> sorted_items;
// first option
typedef boost::any_range<int, boost::forward_traversal_tag, int&, std::ptrdiff_t> my_any_range;
my_any_range r;
if(items.empty())
r = my_any_range(sorted_items);
else
r = my_any_range(items);
for (auto& x : r) {
std::cout << x << " ";
}
// second option
// this could also be a lambda and std::for_each
if(items.empty())
do_stuff(sorted_items.begin(), sorted_items.end());
else
do_stuff(items.begin(), items.end());
return 0;
}
Обе стороны троичного оператора должны иметь одинаковый тип. В вашем случае они разные — std :: vector<> :: iterator и std :: set<> Итератор. Подходящим решением, похоже, является своего рода обертка итератора, которая возвращает то или иное в зависимости от начального условия.
Ошибки верны: авто Ключевое слово работает во время компиляции. Проще говоря, он просто выводит тип назначения и использует это реальный тип. Но решение, является ли он векторным итератором или множеством, принимается во время выполнения. Так что типа нельзя вывести.
Как сказал SergeyA, я здесь не прав, сбой компилятора?: Оператор, до auto. Но причина все та же — он не знает, какой тип использовать для результата.
Возможно, вам следует использовать более общий тип итератора + полиморфизм, или вы можете сделать эту функцию параметризованной по типу, где T — это тип итератора. Я бы предпочел сделать это так:
template<class T> do_stuff(T &c) { for (auto &el : c) { /*Whatever*/ } }
...
if (!items.empty()) {
do_stuff(items);
} else if (!sorted_items.empty()) {
do_stuff(sorted_items);
}
П.С .: Это концепция, я не тестировал код.
auto
означает компилятор выведет тип того, что следует, во время компиляции.
Тип возврата тернарного условного оператора в данном случае следующий за знаком вопроса, поэтому std::set<StuffItem, StuffItemComparator>::iterator
и компилятор пытается привести то, что следует за столбцом (std::vector<StuffItem>::iterator
) к этому несовместимому типу, следовательно ошибка компилятора.
То, что вы можете сделать, это сделать ваш код обработки элементов универсальным, например, так:
auto doStuff = [] (StuffItem& item) {
// do stuff with item...
};
if( holder.items.size() )
for_each( holder.items.begin(), holder.items.end(), doStuff );
else if( holder.sorted_items.size() )
for_each( holder.sorted_items.begin(), holder.sorted_items.end(), doStuff );