Перегрузка оператора [] в шаблоне
Я пытаюсь перегрузить operator[] для экземпляра std:: map и серьезно озадачен ошибками компиляции из GCC.
Следующий пример не скомпилируется:
typedef std::map< int*, int > mymap;
namespace std {
template <>
int & mymap::operator[]( const int* & k) {
return begin()->second;
};
};
Этот терпит неудачу с:
ошибка: идентификатор шаблона 'operator[]<>' для 'int& std::map, std::allocator > >::operator[](const int*&)' не соответствует ни одному объявлению шаблона
Но если вы замените int*
с myintp
(typedef int* myintp
) он будет компилироваться просто отлично.
Также интересно, зачем здесь нужен шаблон<> и пространство имен.
Обновление: я упростил пример.
Разрешается добавлять специализации шаблона для любого стандартного шаблона библиотеки в пространство имен std, только если объявление зависит от типа, определенного пользователем, и специализация удовлетворяет всем требованиям для исходного шаблона, за исключением случаев, когда такие специализации запрещены.
typedef std::map< myclass*, int > mymap;
namespace std {
template <>
int & mymap::operator[]( myclass* const & k) {
return begin()->second;
};
};
Будет ли этот пример обеспечивать законное и предсказуемое поведение?
3 ответа
Тип ключа int*
,
Чтобы соответствовать
T& operator[]( const Key& key );
вам нужно использовать:
int & mymap::operator[]( int* const & k) {
К сожалению, использование const
до того, как тип сбивает с толку. Была ли декларация
T& operator[]( Key const& key );
было бы проще придумать правильное объявление аргумента для того, что вы пытаетесь.
От 17.6.4.2.1/2:
Поведение программы на C++ не определено, если она объявляет
- явная специализация любой функции-члена стандартного шаблона библиотечного класса, или
Так что тут все ставки сняты, и компилятор не обязан компилировать ваш код (другие ответы показывают, почему компилятор принимает код, использующий typedef, но все же не делает его легальным).
C++ 98 немного менее явный, в 17.4.3.1/1:
Для программы на C++ добавление объявлений или определений в пространство имен std или пространства имен в пространстве имен std не определено, если не указано иное. Программа может добавить специализации шаблона для любого стандартного шаблона библиотеки в пространство имен std. Такая специализация (полная или частичная) стандартного шаблона библиотеки приводит к неопределенному поведению, если только объявление не зависит от определенного пользователем имени внешней ссылки и если специализация не соответствует требованиям стандартной библиотеки для исходного шаблона.
Теперь немного неясно, строго ли это запрещает специализацию члена шаблона std
пространство имен (против полной или частичной специализации самого шаблона контейнера), но ваш конкретный код определенно не определен, потому что он не специализируется на определяемом пользователем имени внешней ссылки.
Давайте проанализируем ваш код:
int& mymap::operator[](const int* &k)
{
return begin ()->second;
};
Это неверно, так как параметр является ссылкой на указатель на const int, а не ссылкой на константный указатель на int.
Положение const
вас смутило, так что переписать это так:
int& mymap::operator[](int *const &k)
{
return begin ()->second;
};