2010-02-01 1 views
0

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

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

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

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

но,

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

по теме:

in C++, how to use a singleton to ensure that each class has a unique integral ID?

Assigning Unique Numerical Identifiers to Instances of a Templated Class

ответ

3
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.

Хотя, может быть, я чего-то не хватает?

+0

Я выбрал свой собственный ответ, потому что это) проще и б) статическое время компиляции постоянная , насколько мне известно. – Narfanator

+0

Я тестировал это с VS 2015, и он работает при компиляции для Debug, но не при компиляции для Release. При компиляции для Release оптимизатор объединяет все функции classID() в один. Итак, foo.classID == foo2.classID == foo3.classID. – adigostin

+0

Черт. Нужно найти новый трюк, теперь ... – Narfanator

1

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

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 (найдено в импульсе и других библиотеках и тривиальном писать), которое дает время компиляции постоянная

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]; } 
+0

Проблема с '' is_same'', AFAIK, заключается в том, что она не поддерживает> или <, что означает, что она не сортируется и, следовательно, не может использовать какой-либо эффективный объект хранения, например дерева или карты. – Narfanator

+0

Это отвечает всем требованиям, однако вы указываете, что это не постоянная постоянная времени компиляции? Вы знаете, если мой собственный ответ? (Я думаю, это было бы, но я не уверен, как проверить это.) – Narfanator