Есть вот такое:
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 студии, но можно и без этого условия.
Здравствуйте, 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();
}
};
Здравствуйте, 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>
сабж.
Здравствуйте, ksd, Вы писали:
ksd>сабж.
На всякий случай замечу, что тут просто проблема исчезает сама-собой, если правильно выделить базовый класс.
В общем же случае она решается через
Class template argument deduction (не смотря на то, что полноценно это работает только начиная с C++17, по ссылке также написано как это можно делать и во всех предыдущих версиях языка).
внесите свой template <class T> class BaseGuard внутрь класса Base и сделайте typedef как алияс с новым типом
потом этот новый тип юзайте в наследниках уже без шаблонного имени