Вызовите не виртуальную функцию-член из коллекции указателей базового класса?

0

У меня есть класс 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;
}
  • 0
    Я думаю, что вы сможете достичь того, что ищете, реализовав стирание типов в стиле boost::any . Но я не совсем уверен, какова ваша цель. Не могли бы вы опубликовать весь код, с которым вы работаете - в частности, ваши текущие определения шаблонов функций-членов?
  • 0
    Вы можете использовать шаблон посетителя в основном как есть, с обычным недостатком (посетитель зависит от всех производных классов вместе).
Теги:
templates

4 ответа

2
Лучший ответ

Я не совсем уверен, что вы хотите сделать, но если вы переместите определение шаблона в класс вместо метода, все будет счастливым. Это делает то, что вы хотите?

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;
}
  • 0
    К сожалению нет. Думайте об этих функциях как о распределениях в std::random , которые будут принимать любой генератор случайных чисел в качестве первого входа. Я не хотел бы шаблон с генератором случайных чисел! Я полагаю, мое плохое объяснение требует некоторой проработки.
  • 0
    Я не уверен, почему нет (но я думаю, что я мог упустить момент). Если один объект будет использоваться с одним T, то проблем нет. Если вы планируете использовать разные значения T с одним объектом, шаблонный класс, очевидно, не будет работать. Тем не менее, я бы не стал этого делать, так как это делает обязанности объекта менее определенными. Я не думаю, что вы могли бы редактировать свой вопрос с кодом, который вы хотите работать?
Показать ещё 3 комментария
0

Вы не должны использовать функцию шаблона, а просто передавать делегат в 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) << ',';
}
0

Возможно, вы можете реализовать стирание типа для параметра шаблона функций-членов. Переход с вашим примером 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;
}
0

Скорее всего, вам нужно будет использовать делегатов здесь. Если все классы имеют одинаковое имя и параметры, это так же просто:

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.

  • 0
    Хотя это, кажется, единственный способ достичь того, что я хочу сделать, он кажется очень надуманным и трудным для чтения. Аналог того, что я хочу сделать, это иметь распределения (похожие на те, что в std::random ), которые все наследуются от базового класса, который имеет operator()(pRNG) member operator()(pRNG) который возвращает значение, соответствующее случайному распределению. Кажется ненужным, чтобы я шаблонизировал свою коллекцию в соответствии с используемым типом pRNG . Но не может быть другого пути ...
  • 0
    @ user2899162 вам не нужно шаблонировать вашу коллекцию, если вы удаляете параметр из функции operator() . Может быть, установить параметр с помощью функции set а затем использовать его при вызове operator() ? Это + делегаты приведут к выполнению std::vector<baseWrapper*> vec; ,
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню