передать ссылку на шаблонный класс в нешаблонный
От: ksd Россия  
Дата: 16.07.18 13:32
Оценка:
Есть вот такое:
template <class T>
class Base
{
    std::set<T*> subscribers;
    CriticalSection cs;
public:
    void Lock() {
        cs.Enter();
    }

    void Unlock() {
        cs.Leave();
    }

    void Subscribe(T* s) {
        subscribers.insert(s);
    }

    void UnSubscribe(T* s) {
        subscribers.erase(s);
    }
};

struct Intf
{
    virtual void OnSomeEvent() = 0;
};

class Foo: public Base<Intf>
{
    static void callback(foo* f) {
        f->Lock();
        for (std::set<Intf*>::const_iterator it = f->subscribers.begin(); it != f->subscribers.end(); ++it) {
                    it->OnSomeEvent();
            }
        f->Unlock();
    }
};

class Bar: private Intf
{
public:
    Bar(Foo* f) {
        f.Subscribe(this);
`    }
    void OnSomeEvent() override {
        doSome();
    }
};


как бы так сделать scope guard для foo::callback, чтобы не тащщить везде Intf? т.е. если сделать, например, так:
template < class T >
class BaseGuard
{
    Base<T>& b_;
public:
    BaseGuard(Base<T>& b) : b_(b) {
        b.Lock();
    }
    ~BaseGuard() {
        b_.Unlock();
    }
};

то использование получается такое:
class Foo: public Base<Intf>
{
    static void callback(foo* f) {
        BaseGuard<Intf> bg(*f);
        for (std::set<Intf*>::const_iterator it = f->subscribers.begin(); it != f->subscribers.end(); ++it) {
                    it->OnSomeEvent();
            }
    }
};

вот этот вот <Intf> не нравится.


Примечание. Лучше всего, чтобы код собирался в 2008 студии, но можно и без этого условия.
Re: передать ссылку на шаблонный класс в нешаблонный
От: watchmaker  
Дата: 16.07.18 13:49
Оценка: 3 (1)
Здравствуйте, ksd, Вы писали:

ksd>Есть вот такое:

ksd>template <class T>
ksd>class Base


ksd>вот этот вот <Intf> не нравится.


Казалось бы тут логика работы с CriticalSection никак не зависит от типа T, а значит её можно унести в базовый класс, а не инистанциировать реализацию для каждого T (это действие к тому же положительно сказывается на скорости компиляции, объёме кода, и иногда даже на скорости работы).

То есть написать можно так:

class BaseBase {
    CriticalSection cs;    
public:
    void Lock() {
        cs.Enter();
    }

    void Unlock() {
        cs.Leave();
    }
};

template <class T>
class Base : public BaseBase
{
    std::set<T*> subscribers;
    
public:
    void Subscribe(T* s) {
        subscribers.insert(s);
    }

    void UnSubscribe(T* s) {
        subscribers.erase(s);
    }
};



class BaseGuard
{
    BaseBase& b_;
public:
    BaseGuard(BaseBase& b) : b_(b) {
        b.Lock();
    }
    ~BaseGuard() {
        b_.Unlock();
    }
};
Re[2]: да, пожалуй, так и сделаю
От: ksd Россия  
Дата: 16.07.18 14:00
Оценка:
Здравствуйте, watchmaker, Вы писали:

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


ksd>>Есть вот такое:

W>
ksd>>template <class T>
ksd>>class Base
W>


ksd>>вот этот вот <Intf> не нравится.


W>Казалось бы тут логика работы с CriticalSection никак не зависит от типа T, а значит её можно унести в базовый класс, а не инистанциировать реализацию для каждого T (это действие к тому же положительно сказывается на скорости компиляции, объёме кода, и иногда даже на скорости работы).


W>То есть написать можно так:

W>class BaseBase {
W>    CriticalSection cs;    
W>public:
W>    void Lock() {
W>        cs.Enter();
W>    }

W>    void Unlock() {
W>        cs.Leave();
W>    }
W>};

W>template <class T>
W>class Base : public BaseBase
W>{
W>    std::set<T*> subscribers;
    
W>public:
W>    void Subscribe(T* s) {
W>        subscribers.insert(s);
W>    }

W>    void UnSubscribe(T* s) {
W>        subscribers.erase(s);
W>    }
W>};



W>class BaseGuard
W>{
W>    BaseBase& b_;
W>public:
W>    BaseGuard(BaseBase& b) : b_(b) {
W>        b.Lock();
W>    }
W>    ~BaseGuard() {
W>        b_.Unlock();
W>    }
W>};
W>

сабж.
Re[3]: Class template argument deduction
От: watchmaker  
Дата: 16.07.18 18:28
Оценка:
Здравствуйте, ksd, Вы писали:

ksd>сабж.


На всякий случай замечу, что тут просто проблема исчезает сама-собой, если правильно выделить базовый класс.

В общем же случае она решается через Class template argument deduction (не смотря на то, что полноценно это работает только начиная с C++17, по ссылке также написано как это можно делать и во всех предыдущих версиях языка).
Re: передать ссылку на шаблонный класс в нешаблонный
От: reversecode google
Дата: 16.07.18 18:44
Оценка:
внесите свой template <class T> class BaseGuard внутрь класса Base и сделайте typedef как алияс с новым типом
потом этот новый тип юзайте в наследниках уже без шаблонного имени
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.