#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <tr1/memory>
#include <tr1/functional>


struct Data
{
    int A, B, C;
};


class DataSpecification
{
public:
    virtual bool IsSatisfiedBy(Data&) const = 0;
};

typedef std::tr1::shared_ptr<DataSpecification> DataSpecificationPtr;


class Validator
{
public:
    void AddSpecification(DataSpecificationPtr spec)
    {
        specs_.push_back(spec);
    }

    bool IsValid(Data& data)
    {
        using std::tr1::placeholders::_1;
        return specs_.end() != std::find_if(specs_.begin(), specs_.end(), 
            std::tr1::bind(&DataSpecification::IsSatisfiedBy, _1, data));
    }
private:
    std::vector<DataSpecificationPtr> specs_;
};


class DataLoader
{
public:
    DataLoader(bool breakIfInvalid, const Validator& validator) :
        validator_(validator),
        breakIfInvalid_(breakIfInvalid), 
        a(0), b(1), c(2)
    {

    }

    template<typename OutIter>
    void Load(OutIter out)
    {
        while(HasNext())
        {
            Data data = LoadNext();
            if (!validator_.IsValid(data))
            {
                if (breakIfInvalid_)
                    break;
                else
                    continue;
            }
            out++ = data;
        }
    }

private:

    bool HasNext()
    {
        return a < 10;
    }

    Data LoadNext()
    {
        Data d;
        d.A = a++;
        d.B = b++;
        d.C = c++;
        return d;
    }

    Validator validator_;
    bool breakIfInvalid_;
    int a, b, c;
};


class AGreaterMin : public DataSpecification
{
public:
    AGreaterMin(int minA) : min_(minA){}

    bool IsSatisfiedBy(Data& data) const
    {
        return data.A > min_;
    }
    int min_;
};

class BGreaterMin : public DataSpecification
{
public:
    BGreaterMin(int minB) : min_(minB){}

    bool IsSatisfiedBy(Data& data) const
    {
        return data.B > min_;
    }
    int min_;
};


template<typename DataContainer>
void PrintData(const DataContainer& c)
{
    typedef typename DataContainer::const_iterator Iter;
    for (Iter it = c.begin(), end = c.end(); it != end; ++it)
        std::cout << it->A << " " << it->B << " "  << it->C << "\n";
}
int main()
{
    std::vector<Data> data;
    Validator v;
    v.AddSpecification(DataSpecificationPtr(new AGreaterMin(5)));
    v.AddSpecification(DataSpecificationPtr(new BGreaterMin(7)));


    DataLoader loader1(false, v);
    loader1.Load(std::back_inserter(data));
    PrintData(data);

    data.clear();
    std::cout << "Break if invalid:\n";
    DataLoader loader2(true, v);
    loader2.Load(std::back_inserter(data));
    PrintData(data);
}