У меня есть класс D
, я хочу, чтобы классы A,B,C
наследовали. Тем не менее, функции, которые я хочу объявить как pure virtual
шаблоны.
К сожалению, по словам зрительной студии:
member function templates cannot be virtual
Классы A,B,C
имеют оператор-член, вызываемый точно таким же образом, хотя могут возвращать разные значения (double
или unsigned int
именно. Но я был бы рад заставить его работать с double
):
template<typename T>
double operator()(T&, unsigned int b){/*code*/};
Как я мог правильно создать полиморфную коллекцию классов A,B,C
(аналогично std::vector<D*>
, которая работала бы, если бы я не хотел шаблонов функций-членов), что делает то, что я пытаюсь сделать?
РЕДАКТИРОВАТЬ:
Пример того, что я хотел бы сделать:
std::default_random_engine rng((unsigned int) std::time(0));
std::vector<D*> v;
v.push_back(new A(0.3));
v.push_back(new B(1.0,3.2));
v.push_back(new C);
for(auto x : v){
for(auto y : x->operator()(rng,5){
std::cout << y << ',';
}
std::cout << std::endl;
}
Я не совсем уверен, что вы хотите сделать, но если вы переместите определение шаблона в класс вместо метода, все будет счастливым. Это делает то, что вы хотите?
template<typename T>
class A
{
public :
virtual double operator() (T& t, unsigned int b) = 0;
};
template<typename T>
class B : public A<T>
{
public:
virtual double operator() (T& t, unsigned int b)
{
// code
}
};
РЕДАКТИРОВАТЬ:
Или, учитывая, что вам не нужен шаблон на уровне класса, как насчет перемещения случайного вычисления из полиморфного метода, а затем с простым plymorphic методом для реальной жесткой части. Это предполагает, что вы хотите генерировать только одно случайное число. Если вы хотите больше, вы всегда можете создать вектор случайных чисел, размер которого определяется в конструкции. В любом случае приведенный ниже код демонстрирует, о чем я говорю:
class D
{
public :
template<typename T>
double operator() (T& t, unsigned int b)
{
double calc_rand = t();
return DoStuff(calc_rand, b);
}
protected :
virtual double DoStuff(double rnd_value, unsigned int b) = 0;
};
class A : public D
{
protected :
virtual double DoStuff(double rnd_value, unsigned int b)
{
return rnd_value * b;
}
};
int main(void)
{
std::random_device rd;
A a;
std::cout << a(rd, 5) << std::endl;
}
std::random
, которые будут принимать любой генератор случайных чисел в качестве первого входа. Я не хотел бы шаблон с генератором случайных чисел! Я полагаю, мое плохое объяснение требует некоторой проработки.
Вы не должны использовать функцию шаблона, а просто передавать делегат в rng через виртуальную функцию. Таким образом, вы можете сделать это:
class D
{
virtual double operator()(std::function<int()>, int)=0;
};
И назовите это так:
std::default_random_engine rng;
std::vector<D*> v;
...
for(auto x : v)
{
std::cout << x->operator(std::bind(rng), 5) << ',';
}
Возможно, вы можете реализовать стирание типа для параметра шаблона функций-членов. Переход с вашим примером RNG:
class RandUIntIfc {
public:
virtual ~RandUIntIfc() = 0;
virtual unsigned int min() const = 0;
virtual unsigned int max() const = 0;
virtual unsigned int operator()() = 0;
};
class RandUInt {
public:
template <typename RNG>
explicit RandUInt(RNG& rng);
unsigned int min() const;
unsigned int max() const;
unsigned int operator()();
private:
std::shared_ptr<RandUIntIfc> impl_;
template <typename RNG>
class Impl : public RandUIntIfc {
public:
explicit Impl(RNG& rng);
virtual unsigned int min() const;
virtual unsigned int max() const;
virtual unsigned int operator()();
private:
RNG& ref_;
};
};
Я надеюсь, что все фактические определения членов очевидны. Это оставляет только изменение D
и кода, который его использует:
class D {
public:
virtual ~D() = 0;
virtual double operator()(RandUInt rng, unsigned int b) = 0;
};
std::default_random_engine rng((unsigned int) std::time(0));
RandUInt typeless_rng(rng);
std::vector<D*> v;
// ...
for(auto x : v){
for(auto y : x->operator()(typeless_rng,5){
std::cout << y << ',';
}
std::cout << std::endl;
}
Скорее всего, вам нужно будет использовать делегатов здесь. Если все классы имеют одинаковое имя и параметры, это так же просто:
template <typename T>
class baseWrapper{
double method(T& a, unsigned int b) = 0;
};
template <typename T, typename myClass>
class wrapper: public baseWrapper<T>{
myClass &instance;
double method(T& a, unsigned int b){
return instance.method<T>(a,b);
};
wrapper(myClass &instance){this->instance = instance;};
};
И тогда вы можете создать коллекцию делегатов:
std::vector<baseWrapper<int>*> vec;
A myObject1, B myObject2;
wrapper<int,A> wrapper1(myObject1);
wrapper<int,B> wrapper2(myObject2);
vec.push_back(&wrapper1);
vec.push_back(&wrapper2);
Если функции называются по-разному, вам необходимо передать указатель на функцию в качестве дополнительного параметра или проверить его с помощью SFINAE.
std::random
), которые все наследуются от базового класса, который имеет operator()(pRNG)
member operator()(pRNG)
который возвращает значение, соответствующее случайному распределению. Кажется ненужным, чтобы я шаблонизировал свою коллекцию в соответствии с используемым типом pRNG
. Но не может быть другого пути ...
operator()
. Может быть, установить параметр с помощью функции set
а затем использовать его при вызове operator()
? Это + делегаты приведут к выполнению std::vector<baseWrapper*> vec;
,
boost::any
. Но я не совсем уверен, какова ваша цель. Не могли бы вы опубликовать весь код, с которым вы работаете - в частности, ваши текущие определения шаблонов функций-членов?