Я пытаюсь реализовать функцию разыменования условного указателя. Основная идея заключается в следующем:
return is_pointer(arg) ? *arg : arg
Чтобы ограничить количество необходимых специализаций, я пытаюсь использовать rvalue ссылки для случая, когда arg
не указатель. Вот моя текущая реализация (std::cout
существует исключительно для целей отладки):
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T&& t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return t;
}
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == true, typename std::remove_pointer< T >::type& >::type deref(T t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return *t;
}
Теперь я получаю довольно странное поведение в GCC 4.6. Первая перегрузка используется как для типов без указателей, так и для типов указателей. Очевидно, что при использовании типа указателя он конфликтует со второй перегрузкой. Если я закомментирую второй и вызову следующее, используя первый ...
int q;
int *p = &q;
deref(p);
... соответствующий вывод консоли:
0
Pi
Как возможно, что тип без указателя (согласно std::is_pointer
) также является типом указателя (согласно typeid
) в том же контексте? Конфликт возникает между обеими перегрузками из-за std::is_pointer
, неправильно сообщающего p
как тип без указателя. Кроме того, когда я заменяю ссылку r-значения стандартной ссылкой в первой перегрузке:
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T& t)
Это больше не конфликтует со второй перегрузкой ... Я просто не понимаю, что происходит. Кстати, использование второй перегрузки дает (как и следовало ожидать):
1
Pi
Спасибо за вашу помощь.