setParams для родственной иерархии классов с Variadic Templates
От: gencoder  
Дата: 28.04.17 13:06
Оценка:
Имеется иерархия классов, в которой A — базовый, B — потомок. У A есть защищенное поле m_i, а у B добавляется защищенное поле m_j. Требуется написать метод setParams такой, что при использовании экземпляра класса из разрабатываемой иерархии, он будет принимать правильные параметры и правильно их устанавливать. Т.е. для объекта класса A пример одно значение и установит поле m_i, а для B примет два значения и установит поля m_i и m_j:
A<int>* ptr = new B<int>;
ptr->setParams(1,2); // m_i=1, m_j=2 

A<int>* ptr = new A<int>;
ptr->setParams(3); // m_i=3


моя не очень удачная попытка http://ideone.com/mataBZ


template<class T>
class A {
protected:
    T m_i;
    virtual void m_set(T i) 
    {
        m_i=i;
    };
public:    
    template<typename ... Args>
    void setParams( Args&&... params ) 
    { 
        m_set(std::forward<Args>(params)...); 
    }
    virtual void show()
    { 
        cout << m_i << endl;
    }
};


template<class T, typename ... args>
class B: public A<T> {
protected:
    using A<T>::m_i;
    T m_j;
    virtual void m_set(T i, T j) 
    {
        m_i=i;
        m_j=j;
    }
public:    
    virtual void show() override 
    { 
        cout << m_i << ':' << m_j << endl;
    } 
};


int main() {
    auto a = new A<int>;
    a->setParams(22);
    a->show();
    
    A<int>* b = new B<int>;
    a->setParams(22,23);
    a->show();

    return 0;
}
c++11 variadic template
Re: setParams для родственной иерархии классов с Variadic Te
От: Evgeny.Panasyuk Россия  
Дата: 28.04.17 13:16
Оценка:
Здравствуйте, gencoder, Вы писали:

G>
G>A<int>* ptr = new B<int>;
ptr->>setParams(1,2); // m_i=1, m_j=2 
G>


Судя по тому что родитель ничего не знает о потомке, здесь придётся стирать типы. Например запихнуть std::tuple с параметрами (или указателями на них) в boost::any, а в потомке сделать any_cast (либо сделать более эффективный аналог any для данного случая — тут можно обойтись без аллокации, так как данные живут вверху стэка).
Если опустить runtime проверку типа (что делать в большинстве случаев не нужно), то достаточно передавать void* на tuple, а в потомке делать static_cast.
Отредактировано 28.04.2017 13:19 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 28.04.2017 13:16 Evgeny.Panasyuk . Предыдущая версия .
Re[2]: setParams для родственной иерархии классов с Variadic Te
От: gencoder  
Дата: 28.04.17 13:51
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, gencoder, Вы писали:


G>>
G>>A<int>* ptr = new B<int>;
ptr->>>setParams(1,2); // m_i=1, m_j=2 
G>>


EP>Судя по тому что родитель ничего не знает о потомке, здесь придётся стирать типы. Например запихнуть std::tuple с параметрами (или указателями на них) в boost::any, а в потомке сделать any_cast (либо сделать более эффективный аналог any для данного случая — тут можно обойтись без аллокации, так как данные живут вверху стэка).

EP>Если опустить runtime проверку типа (что делать в большинстве случаев не нужно), то достаточно передавать void* на tuple, а в потомке делать static_cast.

ставиться цель: обойти static_cast.

со static_cast можно вообще ничего не воротить, а просто при наличии указателя ptr на базовый класс преобразовать его в указатель на конкретно переданный класс, например работаем с unique_prt:
auto ptrB = static_cast<B<T>*>(ptr.get());
// а затем работаем как с B
ptrB->setSpecBParams(/*...*/);

вот такие вещи, как раз то и хотелось бы исключить из кода.
Re[3]: setParams для родственной иерархии классов с Variadic Te
От: Evgeny.Panasyuk Россия  
Дата: 28.04.17 14:36
Оценка:
Здравствуйте, gencoder, Вы писали:

G>ставиться цель: обойти static_cast.


Стирать типы придётся. Вот представь что компилятору виден только класс A:
#include "a.hpp"

void foo(A<int> *a)
{
    a->setParams(1, 2., '3');
}

каким образом он должен узнать ожидаемое количество параметров и их типы, и в случае чего выдать ошибку компиляции при неправильном вызове setParams? А главное как он должен различить вызов foo с B<int>* от вызова foo с C<int>*? Это разруливается только динамически, то есть в рантайме.
По тем же соображениям не получится передать через заранее типизированный канал объект (или объекты) произвольного типа не стирая этот тип каким-либо образом.

G>со static_cast можно вообще ничего не воротить, а просто при наличии указателя ptr на базовый класс преобразовать его в указатель на конкретно переданный класс


В этом случае на стороне пользователя нужно знать конкретный тип объекта. Он известен?

Ты лучше попробуй описать изначальную задачу, для чего это вообще потребовалось?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.