2009-09-11 5 views
4

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

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, поскольку каждый элемент получает свой собственный уникальный идентификатор, но я думаю, что мне нужно иметь возможность изменять последовательность на месте, которая «вставляет» doesn ' т. е. делать.
Возможно, я подкрался к неправильному дереву. (С положительной стороны, dayum, но MPL!)

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

Спасибо!

+1

Основная проблема заключается в том, что шаблоны могут быть созданы в разных единицах перевода. Поэтому во время компиляции невозможно присвоить уникальные номера - два TU могут быть скомпилированы одновременно на разных компьютерах! – MSalters

+0

О, и основная проблема, похоже, не является основной проблемой - есть основная цель, которая фактически лучше решена другими способами. – MSalters

ответ

4

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

+0

Хорошо, понимание проверки: Когда компилятор компилирует шаблонный класс, он создает набор инструкций (различные функции), человекочитаемое имя и машиночитаемое имя. Каждая из этих вещей существует в памяти и поэтому имеет адрес памяти, который по определению является уникальным для каждого «экземпляра» шаблона и одинаковым для всех одинаковых «экземпляров» шаблона. std :: type_info, когда вы наследуете его, разрешает доступ к этой информации? std :: typeid (класс c) - это простой способ получить уникальный идентификатор? – Narfanator

+0

Будьте осторожны с требованием «по определению уникального». Например, могут ли функции шаблона быть встроенными и, следовательно, могут существовать многочисленные копии этих функций, встроенные в другие функции. Здесь это не очень важно. Главное, что все типы, включая экземпляры шаблонов классов (но не сами шаблоны), имеют тип type_info, и у них есть заказ, предоставленный компилятором. Этот порядок доступен через 'type_info :: before()'. Точка вывода класса из 'type_info' - это просто адаптировать свой интерфейс для использования в качестве ключа в' std :: map' – MSalters

0

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

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

Если вы делаете это все в один файл заголовка, вы можете использовать __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

Если вы включили RTTI, вы можете Concat имен классов, ваш шаблон будет экземпляром с, а затем возвращает хэш для этой строки. При выборе хорошей хэш-функции, вы уменьшаете вероятность столкновения (и, возможно, вам не нужно 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

Что случилось с использованием 'std :: type_info'? – sbi

+0

std :: type_info в порядке. Но (я думал) его можно отключить по настройкам проекта ... – SadSido

+0

Его можно отключить на некоторых компиляторах. Но это довольно глупо, отключив стандартную функцию C++, которую вы используете. – MSalters

0

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

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

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

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

extern unsigned fooCounter; 

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

или даже

template <...> 
unsigned foo::id = reinterpret_cast<unsigned>(&id); 
+0

Я уверен, что последнее будет неопределенным - ODR постоянный инициализатор должен иметь одинаковое значение во всех единицах перевода. – MSalters

+0

@MSalters, инициализатор в более поздней версии больше не является постоянным выражением, чем в первом. И я только перечитал 3.2 и особенно 3.2/5 и не вижу ничего, что помешало бы более позднему определению. (Reinterpret_cast не сможет скомпилировать реализацию, где unsigned недостаточно, чтобы содержать указатель, но это еще одна проблема). – AProgrammer

+0

Кажется, вы можете быть правы - 3.2/5 упоминания (прежде чем он переходит в исключения для имен const-объектов с внутренней или никакой привязкой) возможность того, что имя относится к одному и тому же сугубому объекту повсюду. Теперь проблема заключается в том, что это вызывает циклическую логику: если применяется ODR, «& id» одно и то же имя везде, и применяется ODR. Но если ODR не применяется, '& id' не одно и то же имя везде, и ODR не применяется. Хммм ... ДР? – MSalters

2

У меня только что был этот кусок хаки, лежащий в моих библиотеках (uintxx - это мои typedefs с очевидными значениями) - работает без 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

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

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

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

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

бы

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

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

Смежные вопросы