Уникальный числовой идентификатор шаблонного класса с использованием адреса функции

Итак, этот вопрос задавали раньше, но я хотел задать вопрос с некоторыми из этих ключевых слов в заголовке.

Проблема проста: как создать шаблонный класс, чтобы для каждого экземпляра шаблона — но не для каждого экземпляра класса — был уникальный числовой идентификатор?

То есть способ дифференцировать:

foo<int> f1;
foo<char> f2;
classID(f1) != classID(f2);

но,

foo<int> f3;
foo<int> f4;
classID(f3) == classID(f4);

Относится к:

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

Назначение уникальных числовых идентификаторов экземплярам шаблонного класса


person Narfanator    schedule 01.02.2010    source источник


Ответы (2)


template<class T>
class Base
{
public:
    static void classID(){}
private:
    T* t;
};

int main()
{
    Base<int> foo;
    Base<int> foo2;
    Base<char> foo3;

    /*
    unsigned int i  = reinterpret_cast<unsigned int>(Base<int>::classID);
    unsigned int ii = reinterpret_cast<unsigned int>(Base<char>::classID);
    unsigned int iii = reinterpret_cast<unsigned int>(Base<int>::classID);
    /*/
    unsigned int i  = reinterpret_cast<unsigned int>(foo.classID);
    unsigned int ii  = reinterpret_cast<unsigned int>(foo2.classID);
    unsigned int iii  = reinterpret_cast<unsigned int>(foo3.classID);
    //*/

    return ((i != ii) + (i <= ii) + (i >= ii)) == 2;
}

Вот как! Он легкий, очень простой и не использует RTTI, хотя и использует смехотворно небезопасный метод reinterpret_cast.

Хотя, может я что-то упускаю?

person Narfanator    schedule 01.02.2010
comment
Я выбрал свой собственный ответ, потому что он а) проще и б) статическая постоянная времени компиляции, на самом деле. - person Narfanator; 11.02.2010
comment
Я тестировал это с VS 2015, и это работает при компиляции для отладки, но не при компиляции для выпуска. При компиляции для выпуска оптимизатор объединяет все функции classID() в одну. Итак, foo.classID == foo2.classID == foo3.classID. - person adigostin; 17.03.2016

Я думаю, вы можете просто использовать для этого статическую функцию и наследовать ее класс:

struct IdCounter { static int counter; };
int IdCounter::counter;

template<typename Derived>
struct Id : IdCounter {
  static int classId() {
    static int id = counter++;
    return id;
  }
};

struct One : Id<One> { };
struct Two : Id<Two> { };

int main() { assert(One::classId() != Two::classId()); }

Конечно, это не будет статической константой времени компиляции - я не думаю, что это возможно автоматически (вам придется вручную добавлять эти типы в какой-либо список типов, например mpl::vector). Обратите внимание, что для простого сравнения типов на равенство вам все это не нужно. Вам просто нужно использовать is_same (найденный в boost и других библиотеках и тривиальный для написания), который дает постоянную времени компиляции

template<typename A, typename B>
struct is_same { static bool const value = false; };
template<typename A> 
struct is_same<A, A> { static bool const value = true; };

int main() { char not_true[!is_same<One, Two>::value ? 1 : -1]; }
person Johannes Schaub - litb    schedule 01.02.2010
comment
Проблема с is_same, насколько мне известно, заключается в том, что он не поддерживает › или ‹, что означает, что он не поддается сортировке и, следовательно, не может использовать какой-либо эффективный объект хранения, такой как дерево или карта. - person Narfanator; 02.02.2010
comment
Это соответствует всем требованиям, однако вы указываете, что это не статическая константа времени компиляции? Вы знаете, если мой собственный ответ? (Я думаю, что да, но я не уверен, как это проверить.) - person Narfanator; 02.02.2010