&* для исходного указателя, итератора и std::nullptr_t

У меня есть функция шаблона, которая включена (через std::enable_if), ее параметр является необработанным указателем, или имеет категорию std::iterator, или является std::nullptr_t. В этой функции необработанный указатель (элемент данных) устанавливается равным параметру, например:

template<class T> void myFunction(T it) 
{
    _ptr = &*it;
}

&* хорошо работает для указателя и итератора... но не работает для std::nullptr_t. Есть ли какое-либо решение, позволяющее избежать написания двух разных функций?

Спасибо.


person Vincent    schedule 31.08.2012    source источник
comment
Даже &*it не будет работать, если тип *it перегрузил operator&.   -  person Nawaz    schedule 31.08.2012


Ответы (2)


Самое простое — изменить функцию так, чтобы она имела две перегрузки: одну для необработанных указателей/nullptr_t, которая просто сохраняет значение, и одну, выбранную SFINAE для итераторов с вашей текущей реализацией, хотя следует учитывать, что при некоторых обстоятельствах это не удастся (в частности если iterator::value_type перегружает унарный operator&).

person David Rodríguez - dribeas    schedule 31.08.2012

Как всегда, мы можем решить эту проблему с помощью trait. На этот раз давайте не будем писать полный класс, так как достаточно простой перегрузки функции.

#include <cstddef>
#include <memory>

template <typename T>
T get_addr(T t) { return std::addressof(*t); } // #1

std::nullptr_t get_addr(std::nullptr_t np) { return np; }

Использование:

T _ptr = get_addr(it);

(Эта черта также работает, если тип, на который указывает T, перегружает operator&.)

Вам предлагается охранять перегрузку #1 с тем же условием enable_if, что и в основном шаблоне.

person Kerrek SB    schedule 31.08.2012
comment
Как всегда черта - на этот раз ‹- что это мне положено, простите не смог понять - person Mr.Anubis; 31.08.2012
comment
Вам лучше также сделать особый случай указателей, чтобы предотвратить разыменование указателей, которые не указывают на действительные вещи. template <typename T> T* get_addr(T* t) { return t;} - person orlp; 31.08.2012
comment
@nightcracker: я предполагаю, что OP будет использовать это только внутри функции enable-if'ed. В остальном вы правы конечно. - person Kerrek SB; 31.08.2012
comment
@KerrekSB: никогда не знаешь. Не повредит ли это добавить? Я могу это сделать, если вы не возражаете. - person orlp; 31.08.2012
comment
@Mr.Anubis: Обычно я бы создавал трейты классы со статическими функциями-членами. Однако на этот раз перегруженная функция работает просто отлично. - person Kerrek SB; 31.08.2012
comment
@nightcracker: ОП также хочет использовать это для итераторов, так что нет, не будем. Тем не менее, ему рекомендуется использовать собственное ограничение enable_if для шаблонной перегрузки! - person Kerrek SB; 31.08.2012
comment
@KerrekSB, но опять же, если вы будете писать классы признаков, вам придется специализироваться на std::nullptr_t, что в основном то же самое, что и перегруженные функции, даже больше, не так ли? Спасибо - person Mr.Anubis; 31.08.2012
comment
@Mr.Anubis: Правильно, поэтому в этой ситуации я предпочитаю набор перегрузок функций, а не набор специализаций шаблонов классов. - person Kerrek SB; 31.08.2012
comment
@Mr.Anubis: вот пример черты, которая действительно должна быть шаблоном класса :-) - person Kerrek SB; 01.09.2012
comment
@Luc Danton: Спасибо за исправление! - person Kerrek SB; 01.09.2012
comment
@KerrekSB Это использование sfinae, я не вижу никаких признаков, не так ли? . Хотя за ссылку спасибо :) - person Mr.Anubis; 01.09.2012
comment
@Mr.Anubis: Все это - черта, которая проверяет, является ли что-то производным от класса шаблона ... черта - это довольно общая концепция извлечения конкретной информации об общем параметре. - person Kerrek SB; 01.09.2012