Присвоение уникальных числовых идентификаторов экземплярам шаблонного класса - PullRequest
4 голосов
/ 11 сентября 2009

Основная проблема: Я хочу иметь возможность взять экземпляр шаблонного класса, скажем:

template<class a, class b, class c> class foo;

foo<int, float, double>;

и затем сделайте что-то вроде:

foo<int, float, double>::value;  //Evaluates to a unique number
foo<long, float, double>::value; //Evaluates to a different unique number
foo<int, float, double>::value;  //Evaulates to the same unique number

За исключением, на самом деле, это:

template<class a, class b, class c>
int getUniqueIdentifier()
{
    return foo<a, b, c>::value;
} 

Текущая попытка решения:
Я думаю, что хочу использовать «Расширяемую ассоциативную последовательность» Boost :: MPL, так как каждый элемент получает свой уникальный идентификатор, но я думаю, что мне нужно иметь возможность изменять последовательность на месте, чего «вставка» не делает .
Я могу лаять не на то дерево. (С положительной стороны, дайум, но MPL!)

Назначение:
Изобретая колесо в системе «Сигналы и розетки». Компоненты создают и регистрируют каналы с помощью «коммутатора», который использует уникальные идентификаторы для размещения каналов на карте, что обеспечивает универсальность во время выполнения. Я попытался найти библиотеку Qt в качестве примера, но я не могу разобрать их сокращения, и мне кажется, что мне не хватает формального ноу-хау.

Спасибо!

Ответы [ 8 ]

4 голосов
/ 11 сентября 2009

Если вы хотите поместить вещи на карту и вам нужен ключ для каждого типа, правильное решение - использовать std::type_info::before(). Может быть целесообразно получить класс, чтобы вы могли предоставить operator<, или же обернуть std::type_info::before() в двоичный предикат.

2 голосов
/ 11 сентября 2009

Мне только что повезло, что этот кусок хакерства лежал в моих библиотеках (uintxx - мои определения типов с очевидным значением) - работает без rtti 32/64 соотв. первые несколько шаблонов должны определить pointer_uint, который содержит пустоту *

namespace pgast{

template <size_t size>
struct _pointer_uint{
};

template <>
struct _pointer_uint<2>{
    typedef uint16 intrinsic;
};

template <>
struct _pointer_uint<3>{
    typedef uint32 intrinsic;
};

template <>
struct _pointer_uint<4>{
    typedef uint32 intrinsic;
};

template <>
struct _pointer_uint<5>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<6>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<7>{
    typedef uint64 intrinsic;
};

template <>
struct _pointer_uint<8>{
    typedef uint64 intrinsic;
};

typedef _pointer_uint< sizeof(void*) >::intrinsic pointer_uint; 

template <class c>
struct Class_Identifier{
   static pointer_uint id(){
       static char _id;
       return reinterpret_cast<pointer_uint>(&_id);
   }
   template <class c2> 
   bool operator==(const Class_Identifier<c2>& rhs)const{
      return id() == Class_Identifier<c2>::id();
   }
   template <class c2> 
   bool operator<(const Class_Identifier<c2>& rhs)const{
      return id() < Class_Identifier<c2>::id();
   }
};

}//namespace pgast

/*
Copyright (c)1993,2001 J. E. Pendergast Jr. 
*/
0 голосов
/ 13 декабря 2009

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

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

Так, например;

template<class a>
foo
{
    void id(){}
    ...
}

будет

&foo<int>::id != &foo<float>::id  //?

Если это так, то я могу использовать его в качестве своего уникального идентификационного номера для каждой карты, а не полагаться на RTTI.

0 голосов
/ 11 сентября 2009

Вы хотите, чтобы это было для каждого экземпляра или для каждого экземпляра? Для более поздних

template <...>
class foo 
{
public:
   static unsigned id;
};

extern unsigned fooCounter;

template <...>
unsigned foo::id = ++fooCounter;

или даже

template <...>
unsigned foo::id = reinterpret_cast<unsigned>(&id);
0 голосов
/ 11 сентября 2009

Или как насчет:

template<class a, class b, class c, int uniqueId>
class Test
{
public:
    int uid() {
        return uniqueId;
    }
};

int main(int argc, char* argv[])
{
    Test<int, int, int, 5> test1;

    std::cout << test1.uid() << std::endl;

    return 0;
}

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

template<class a, class b, class c>
class TestId5 : public Test<a, b, c, 5>{};
0 голосов
/ 11 сентября 2009

Если у вас включен rtti, вы можете объединить имена классов, с которыми создается ваш шаблон, а затем вернуть хеш для этой строки. Выбирая хорошую хэш-функцию, вы минимизируете вероятность коллизии (и, возможно, вам также не нужен rtti, вы можете ввести некоторые собственные rtti):

// basic template for gaining names of the classes:
template<typename T>
class Rtti
{
static std::string GetRTTIName() { return std::string(); }
};

// specialization for the classes, you expect to use:
template<>
class Rtti<float>
{
static std::string GetRTTIName() { return std::string("float"); }
};
0 голосов
/ 11 сентября 2009

Если вы делаете все это в одном заголовочном файле, вы можете использовать макрос __LINE__, чтобы получить какой-то уникальный номер. Однако, как только это распространяется на более чем один файл, они перестают быть уникальными.

IIRC, VC имеет некоторый макрос, который оценивает число, которое увеличивается каждый раз, когда макрос используется. Так что, если вы только на VC, вы можете использовать это. Однако это также будет работать только в пределах одного блока перевода.

Кроме этого, я понятия не имею, как получить уникальные числа из типов.

Однако, почему бы вам не использовать typeid в качестве типа ключа карты? Примерно так:

typedef std::map< std::type_info, whatever > my_map;

template< typename a, typename b, typename c>
void register_foo(my_map& the_map, const foo<a,b,c>& some_bar, whatever the_whatever) 
{
  the_map.insert( typeid(foo<a,b,c>), the_whatever );
}
0 голосов
/ 11 сентября 2009

Вероятность столкновений велика, но для простоты вы не можете победить:

template<class a, class b, class c>
static int getUniqueIdentifier()
{
    return sizeof( a ) + sizeof( b ) + sizeof( c );
}
...