Инициализация статической константы в классе, расширяющем шаблон

Рассмотрим этот псевдокод:

class Foo {
public:
    virtual int getID() const = 0;
}

template<typename T>
class Blah : public Foo {
public:
    T data;
    static const int ID;  //static ID
    int getID() const { return Blah<T>::ID; }  //instance returns the ID
}

class Dude : public Blah<int> {
}
int Dude::ID = 10;  //I want to define Blah<int>::ID here, but how?

int receive(const Foo& foo) {
    if(foo.getID() == Dude::ID) {
        cout << "Received a Dude" << endl;
    }
}

Этот фрагмент кода не компилируется, поскольку ISO C++ не позволяет определить идентификатор в шаблоне Blah как идентификатор в классе Dude. Я понимаю, почему, потому что у меня может быть несколько классов, расширяющих Blah<int>.

Я понимаю, что если я поставлю template<typename T> int Blah<T>::ID = 10' in the Blah<T> impl, он будет работать... но это не то, чего я хочу... Я хочу, чтобы производный класс определял идентификатор...

Должен ли я вставлять идентификатор и getID() в производный класс? Думаю, в конечном итоге меня интересует некоторый RTTI, чтобы я мог правильно обработать Foo. Если у кого-то есть лучший образец, я все уши.

EDIT В ответ на некоторые комментарии... Я хотел бы однозначно идентифицировать классы, производные от Foo, с помощью некоторого идентификатора, чтобы я мог сравнить идентификатор среды выполнения некоторого объекта Foo с идентификатором определенного класса.

Спасибо!


person Tim Reddy    schedule 24.03.2011    source источник
comment
Я не уверен, что правильно понимаю проблему. Вы проверяли CRTP? Это может быть полезно здесь. en.wikipedia.org/wiki/Curiiously_recurring_template_pattern   -  person Asha    schedule 24.03.2011
comment
@Asha: я не знаком с CRTP ... но я не думаю, что хочу вывести Dude, используя себя в качестве параметра шаблона.   -  person Tim Reddy    schedule 24.03.2011
comment
Вы спрашиваете о шаге, а не цели, что делает невозможно ответить. Что вы пытаетесь достичь?   -  person GManNickG    schedule 24.03.2011
comment
@GMan: Удобная ссылка... спасибо... и я обновил свой вопрос.   -  person Tim Reddy    schedule 24.03.2011
comment
@TReddy: Возможно, я неправильно понял вопрос, но разве typeid или dynamic_cast не соответствуют цели?   -  person Ise Wisteria    schedule 24.03.2011
comment
@Ise: Учитывая, что любой тип Foo может быть передан в receive, в некоторых случаях переключатель лучше, чем блок if/else, особенно для классов с большой реализацией receive.   -  person Tim Reddy    schedule 24.03.2011


Ответы (3)


Сделать статический идентификатор int; private и предоставить GetID в общедоступном интерфейсе, сделать SetID защищенным интерфейсом. Но это не очень хорошее решение, потому что все производные классы будут иметь один и тот же идентификатор, а это не то, что вам нужно.

Лучше использовать идентификатор в качестве параметра шаблона базового класса, тогда класс Derived: public Base‹234>{} будет работать.

Или добавьте в базовый класс виртуальную константу int GetID() = 0.

person Shuo    schedule 24.03.2011

Я думаю, вы можете просто сделать это:

class Dude : public Blah<int> {
}
 static const int Dude_ID; //declaration!

int receive(const Foo& foo) {
    if(foo.getID() == Dude::Dude_ID) {
        cout << "Received a Dude" << endl;
    }
}
static const int Dude::Dude_ID = 10; // definition!

Точно так же определите идентификатор для каждого производного класса.


Еще один способ получить идентификатор для каждого класса:

template<typename T, int ID=1>
class Blah : public Foo {
public:
    int getID() const { return ID; }  
}

template<int ID=10>
class Dude : public Blah<int> {
public:
    int getID() const { return ID; }  
}
person Nawaz    schedule 24.03.2011
comment
Я упоминаю ваш ответ в своем вопросе... Мне просто интересно, смогу ли я избежать всего этого шаблонного кодирования, потому что у меня есть десятки классов, которые расширяют Бла... - person Tim Reddy; 24.03.2011
comment
Понятно... пара вопросов... вы хотите сделать Dude шаблонным классом... не могли бы вы просто сказать class Dude: public Blah‹T, 10›? - person Tim Reddy; 24.03.2011
comment
@T Reddy: Да, чувак, теперь шаблон класса. И поскольку ID имеет значение по умолчанию, это означает, что вы не можете передавать ему аргумент. Blah<int> достаточно! - person Nawaz; 24.03.2011
comment
@T Редди: Конечно. Но у вас немного другой синтаксис, если вы не хотите передавать аргумент (поскольку параметр шаблона Dude имеет значение по умолчанию), сделайте следующее: new Dude<>(). В противном случае сделайте так: new Dude‹10›()`. - person Nawaz; 24.03.2011
comment
Я не думаю, что это сработает для меня, потому что, например, новый Чувак‹›() не то же самое, что новый Чувак‹1›()… Чувак – это просто Чувак, ИМХО… ;) - person Tim Reddy; 24.03.2011
comment
@T Reddy: Тогда зачем тебе ID? Все чуваки не одинаковы! - person Nawaz; 24.03.2011
comment
потому что идентификатор принадлежит Foo... и он однозначно идентифицирует класс Foo... в данном случае Dude - person Tim Reddy; 24.03.2011

Я нашел этот ответ, который делает именно то, что мне нужно... извините, если мой вопрос сбил с толку.

как в C++ использовать синглтон, чтобы гарантировать, что каждый класс имеет уникальный интегральный идентификатор?

person Tim Reddy    schedule 24.03.2011