Если вам не повезло иметь дело с окончаниями окон Windows, вам нужно удалить \r
и \n
tr '[\r\n]' ' ' < $input > $output
Есть два варианта. Самый простой - использовать что-то вроде remove_copy_if
. Я не могу объяснить, почему они так называют, но он копирует элементы из одного контейнера в другой, которые не удовлетворяют предикату. Вот основная идея (непроверенная):
struct IsDog : unary_function < Animal *, bool > {
bool operator ()(Animal * animal) const {
return dynamic_cast <Dog*> (animal);
}
};
void foo (vector<Animal*> animals) {
vector<Dog*> dogs;
std::remove_copy_if (animals.begin ()
, animals.end ()
, back_inserter (dogs)
, std::not1 ( IsDog () ) ); // not1 here negates the result of IsDog!
// dogs now contains only animals that were dogs
}
Я полагаю, что способ взглянуть на remove_copy_if
- это представить его как copy_unless
.
Альтернативный подход, если вы основываете свой код только на итераторах, нужно обернуть итератор для vector
class dog_iterator // derive from std::iterator probably with bidirectinoal tag
{
private:
vector<Animals*>::iterator getNextDogIter (vector<Animals*>::iterator iter) {
while (iter != m_end) {
if (0 != dynamic_cast<Dog*> (*iter)) {
break;
}
++iter;
}
return iter;
}
public:
dog_iterator (vector<Animals*>::iterator iter, vector<Animals*>::iterator end)
: m_end (end)
, m_iter (getNextDogIter (iter))
{
}
// ... all of the usual iterator functions
dog_iterator & operator++ ()
{
// check if m_iter already is at end - otherwise:
m_iter = getNextDogIter (m_iter + 1);
return *this;
}
// ...
};
Это очень грубо,
Вы можно использовать std :: transform
. Он по-прежнему использует для ()
внутри, но вы получите двухстрочную реализацию:
#include <vector>
#include <algorithm>
using namespace std;
struct Animal { virtual ~Animal() {} };
struct Dog : Animal { virtual ~Dog() {} };
template<typename Target>
struct Animal2Target { Target* operator ()( Animal* value ) const { return dynamic_cast<Target*>(value); } };
void myDogCallback(vector<Animal*> &animals) {
{
vector<Dog*> dogs;
transform( animals.begin(), animals.end(), dogs.begin(), Animal2Target<Dog>() );
}
Ваш код в том виде, в каком он написан, помещает кучу нулевых указателей в вектор ваших собак, когда вектор животных содержит другие специализации животных.
vector<Dog*> dogs;
vector<Animal*>::iterator iter;
Dog* dog;
for( iter = animals.begin(); iter != animals.end(); ++iter )
{
dog = dynamic_cast<Dog*>(*iter);
if( dog )
{
dogs.push_back( dog );
}
}
Обычно использовать dynamic_cast для понижающего преобразования не очень хорошо. Вам, вероятно, следует провести рефакторинг своего кода, чтобы не использовать явное понижающее преобразование.
См. CPP FAQ lite для получения дополнительной информации.
UPD Также см. Страница Stroustrup (поиск «Почему я не могу назначить вектор вектору?»)
Если вы говорите, что можете гарантировать, что каждый элемент действительно является собакой, тогда просто static_cast
т.е.
void myDogCallback(vector<Animal*> &animals) {
const vector<Animal*>::size_type numAnimals = animals.size();
vector<Dog*> dogs;
dogs.reserve( numAnimals );
for ( vector<Animal*>::size_type i = 0; i < numAnimals; ++i ) {
dogs.push_back(static_cast<Dog*>( animals[i] ));
}
}
I обычно люди всегда получают резкую реакцию о том, что это плохо, и вы всегда должны использовать dynamic_cast
, но на самом деле, если вы можете дать гарантии о типе, то это совершенно безопасно, и ИМО - разумный поступок. .
Кроме того, ваша гарантия будет означать, что новый вектор имеет тот же размер, поэтому зарезервируйте то же пространство, чтобы избежать выделения в каждом push_back
. В качестве альтернативы петля I '