samedi 19 avril 2014

modèles - méthode virtuelle C++ prend les itérateurs STL-style - Stack Overflow


I want to have an interface ModelGenerator which has a method generate() that takes an iterable list of Evidence and creates a Model. Using the STL pseudo-duck-typing iterator idiom...


template<class Model>
class ModelGenerator {
public:
template<class Iterator>
virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

But virtual functions can’t be templated. So I have to template the whole class:


template<class Model, class Iterator>
class ModelGenerator {
public:
virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

Ideally what I’d like to do is something like this...


template<class Model, class Evidence>
class ModelGenerator {
public:
virtual bool generate(iterator<Evidence>& begin,
iterator<Evidence>& end,
Model& model) = 0;
};

But there is no such interface that iterators inherit from. (The class std::iterator only contains a bunch of typedefs, no methods.)


The only way I can think of doing it is to give ModelGenerator a method addEvidence() which adds them one by one before calling generate(), but then I have to give the ModelGenerator state which is a bit of a pain.


How can I write a virtual method that takes any STL container?




You seem to need an any_iterator. That's an iterator that performs type erasure to insulate you from the actual iterator implementation.


Adobe has an implementation of any_iterator: http://stlab.adobe.com/classadobe_1_1any__iterator.html


Boost has an implementation of any_range: http://www.boost.org/doc/libs/1_49_0/libs/range/doc/html/range/reference/ranges/any_range.html




You could consider to use template specialisation instead of virtual methods to this end. From what I understand, you have a unique Evidence class, a number of distinct Model classes and whant to create a generic factory to produce a selected Model from a sequence of Evidences.


#include <vector>
#include <iostream>

struct Model1 { };
struct Model2 { };
struct Evidence { };

template<class Model>
struct ModelGenerator;

template<>
struct ModelGenerator<Model1>
{
typedef Model1 model_type;

template<class Iterator>
model_type generate(Iterator begin, Iterator end)
{
std::cout << "Generate Model1\n";
return model_type();
}
};

template<>
struct ModelGenerator<Model2>
{
typedef Model2 model_type;

template<class Iterator>
model_type generate(Iterator begin, Iterator end)
{
std::cout << "Generate Model2\n";
return model_type();
}
};

template<class Model, class Iterator>
Model make_model(Iterator begin, Iterator end)
{
ModelGenerator<Model> gen;
return gen.generate(begin, end);
}

You can use it this way:


int main()
{
std::vector<Evidence> v;

Model1 m1 = make_model<Model1>(v.begin(), v.end());
Model2 m2 = make_model<Model2>(v.begin(), v.end());
}


I want to have an interface ModelGenerator which has a method generate() that takes an iterable list of Evidence and creates a Model. Using the STL pseudo-duck-typing iterator idiom...


template<class Model>
class ModelGenerator {
public:
template<class Iterator>
virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

But virtual functions can’t be templated. So I have to template the whole class:


template<class Model, class Iterator>
class ModelGenerator {
public:
virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

Ideally what I’d like to do is something like this...


template<class Model, class Evidence>
class ModelGenerator {
public:
virtual bool generate(iterator<Evidence>& begin,
iterator<Evidence>& end,
Model& model) = 0;
};

But there is no such interface that iterators inherit from. (The class std::iterator only contains a bunch of typedefs, no methods.)


The only way I can think of doing it is to give ModelGenerator a method addEvidence() which adds them one by one before calling generate(), but then I have to give the ModelGenerator state which is a bit of a pain.


How can I write a virtual method that takes any STL container?



You seem to need an any_iterator. That's an iterator that performs type erasure to insulate you from the actual iterator implementation.


Adobe has an implementation of any_iterator: http://stlab.adobe.com/classadobe_1_1any__iterator.html


Boost has an implementation of any_range: http://www.boost.org/doc/libs/1_49_0/libs/range/doc/html/range/reference/ranges/any_range.html



You could consider to use template specialisation instead of virtual methods to this end. From what I understand, you have a unique Evidence class, a number of distinct Model classes and whant to create a generic factory to produce a selected Model from a sequence of Evidences.


#include <vector>
#include <iostream>

struct Model1 { };
struct Model2 { };
struct Evidence { };

template<class Model>
struct ModelGenerator;

template<>
struct ModelGenerator<Model1>
{
typedef Model1 model_type;

template<class Iterator>
model_type generate(Iterator begin, Iterator end)
{
std::cout << "Generate Model1\n";
return model_type();
}
};

template<>
struct ModelGenerator<Model2>
{
typedef Model2 model_type;

template<class Iterator>
model_type generate(Iterator begin, Iterator end)
{
std::cout << "Generate Model2\n";
return model_type();
}
};

template<class Model, class Iterator>
Model make_model(Iterator begin, Iterator end)
{
ModelGenerator<Model> gen;
return gen.generate(begin, end);
}

You can use it this way:


int main()
{
std::vector<Evidence> v;

Model1 m1 = make_model<Model1>(v.begin(), v.end());
Model2 m2 = make_model<Model2>(v.begin(), v.end());
}

0 commentaires:

Enregistrer un commentaire