Как получить тип по указателю на него?
От: LazyKarlson  
Дата: 25.06.18 20:34
Оценка:
Что хочется: как-нибудь автоматически вывести тип, на который указывает указатель, имея только тип самого указателя.
Пример:
template < class T > class C
{
public:
    C (T* t) {};
};

struct S
{
    int _internal;
};

S* CreateS()
{
    return new S();
}

typedef S* PS;

int main()
{
    PS p = CreateS();

    // Как получается
    C < S > c1(p);

    // Как хотелось бы, но не получается:
    C < *PS > c2(p);
    // Или что-то подобное.
}

Зачем: бывает так, что указатель описан в API,а то, на что он указывает, нет.

Откуда ноги поросли: Захотел HKEY из Win32 обернуть в unique_ptr с RegCloseKey в качестве deleter'a. Все хорошо, только в качестве типа в конструктор unique_ptr приходится передавать HKEY__, а не *HKEY или что-то подобное.
Re: Как получить тип по указателю на него?
От: watchmaker  
Дата: 25.06.18 20:48
Оценка: 3 (2)
Здравствуйте, LazyKarlson, Вы писали:

LK>автоматически вывести тип, на который указывает указатель, имея только тип самого указателя.


std::remove_pointer_t
Re: Как получить тип по указателю на него?
От: Gaia  
Дата: 26.06.18 11:38
Оценка: 2 (1)
Здравствуйте, LazyKarlson, Вы писали:

LK>Откуда ноги поросли: Захотел HKEY из Win32 обернуть в unique_ptr с RegCloseKey в качестве deleter'a. Все хорошо, только в качестве типа в конструктор unique_ptr приходится передавать HKEY__, а не *HKEY или что-то подобное.


Конкретно для std::unique_ptr есть альтернатива — определенный тип pointer у класса Deleter'а


struct RegKeyDeleter
{
  using pointer = HKEY;
  void operator()(pointer p) const
  { 
     RegCloseKey(p);
  }
};

using unique_reg_key = std::unique_ptr<HKEY, RegKeyDeleter>;
Re[2]: Как получить тип по указателю на него?
От: LazyKarlson  
Дата: 26.06.18 16:40
Оценка:
Здравствуйте, Gaia, Вы писали:

G>Конкретно для std::unique_ptr есть альтернатива — определенный тип pointer у класса Deleter'а



G>
G>struct RegKeyDeleter
G>{
G>  using pointer = HKEY;
G>  void operator()(pointer p) const
G>  { 
G>     RegCloseKey(p);
G>  }
G>};

G>using unique_reg_key = std::unique_ptr<HKEY, RegKeyDeleter>;
G>


Тоже работает, да, хотя введение дополнительной структуры.. ну.. шашечки. Но я не об этом. Не могу понять, почему вот так
struct RegKeyDeleter
{
    //using pointer = HKEY;
    void operator()(HKEY p) const
    {
        RegCloseKey(p);
    }
};

using unique_reg_key = std::unique_ptr<HKEY, RegKeyDeleter>;

не работает? Я всего лишь убрал переопределение типа...
Re[3]: Как получить тип по указателю на него?
От: Кодт Россия  
Дата: 26.06.18 20:28
Оценка: 3 (2)
Здравствуйте, LazyKarlson, Вы писали:

LK>Тоже работает, да, хотя введение дополнительной структуры.. ну.. шашечки. Но я не об этом. Не могу понять, почему вот так

LK>
LK>struct RegKeyDeleter
LK>{
LK>    //using pointer = HKEY;
LK>    void operator()(HKEY p) const
LK>    {
LK>        RegCloseKey(p);
LK>    }
LK>};

LK>using unique_reg_key = std::unique_ptr<HKEY, RegKeyDeleter>;
LK>

LK>не работает? Я всего лишь убрал переопределение типа...

Потому что так задумано. Чтобы можно было хранить в unique_ptr произвольные указатели.
https://en.cppreference.com/w/cpp/memory/unique_ptr
unique_ptr<T,Deleter> берёт тип "указатель" из Deleter::pointer, либо, если это не указано, считает указателем тип T*.

Правда, совсем уж произвольные типы там хранить не получится, (например, int с сигнальным значением -1 — всякие позиксовые дескрипторы).
А только NullablePointer.

Кстати говоря, HKEY тоже формально нельзя хранить: у него сигнальное значение INVALID_HANDLE_VALUE = (HKEY)(intptr_t)(-1).
Но практика показывает, что в WinAPI не встречаются хэндлы со значением 0. То есть, мы не получим здесь утечку ресурсов из-за того, что unique_ptr((HKEY)0) откажется вызывать RegCloseKey.

Кстати говоря!
Если уж писать на плюсах под WinAPI, то было бы очень естественно взять библиотеку ATL, в которой есть умные хэндлы. Конкретно, здесь — CRegKey.
Ну или если ATL тащить не хочется, то скопипастить своё — это же дело пары минут. Там не рокет саенс, всего-то — написать кучу стандартных методов.

class RegKey {
public:
  RegKey() {}
  explicit RegKey(HKEY h) : h_(h) {}
  RegKey(RegKey&& r) { r.swap(*this); }

  ~RegKey() { if (h_ != INVALID_HANDLE_VALUE) ::RegCloseKey(h_); }

  RegKey& operator = (HKEY h) { return *this = RegKey(h); }
  RegKey& operator = (RegKey&& r) { r.swap(*this); return *this; }

  void swap(RegKey& r) { swap(h_, r.h_); }

  HKEY detach() { HKEY h = h_; h_ = INVALID_HANDLE_VALUE; return h; }
  HKEY get() const { return h_; }
  // operator * и -> смысла не имеют, т.к. HKEY не разыменуемый

  operator bool() const { return h_ != INVALID_HANDLE_VALUE; }

private:
  HKEY h_ = INVALID_HANDLE_VALUE;
};
Перекуём баги на фичи!
Отредактировано 27.06.2018 8:24 Кодт . Предыдущая версия .
Re[2]: Как получить тип по указателю на него?
От: rg45 СССР  
Дата: 27.06.18 07:23
Оценка: 15 (2)
Здравствуйте, watchmaker, Вы писали:

LK>>автоматически вывести тип, на который указывает указатель, имея только тип самого указателя.


W>std::remove_pointer_t


Да, но не стоит только забывать, что std::remove_pointer применим не только к указателям, а вообще к любым типам. Между тем, ТС собирается применять это к алиасам типов, для которых не известно, является ли данный тип указателем, или чем-то другим. Возможно, имело бы смысл определить собственную метафункцию, во избежание "сюрпризов". Ну хотя бы так:

template <typename, typename = void>
struct MySpecialRemovePointer;

template <typename T>
struct MySpecialRemovePointer<T, std::enable_if_t<std::is_pointer<T>::value>> : std::remove_pointer<T> {};
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 28.06.2018 6:28 rg45 . Предыдущая версия . Еще …
Отредактировано 27.06.2018 7:40 rg45 . Предыдущая версия .
Отредактировано 27.06.2018 7:30 rg45 . Предыдущая версия .
Re[4]: Как получить тип по указателю на него?
От: LazyKarlson  
Дата: 27.06.18 17:18
Оценка:
К>Кстати говоря!
К>Если уж писать на плюсах под WinAPI, то было бы очень естественно взять библиотеку ATL, в которой есть умные хэндлы. Конкретно, здесь — CRegKey.
К>Ну или если ATL тащить не хочется, то скопипастить своё — это же дело пары минут. Там не рокет саенс, всего-то — написать кучу стандартных методов.


Оно да, но там надо пару ключей считать. Для этого ни ATL подключать, ни дополнительную структуру создавать не хотелось.

А вот вывод указателя из Deleter::pointer был для меня откровением. Спасибо!
Re[3]: Как получить тип по указателю на него?
От: rg45 СССР  
Дата: 28.06.18 06:25
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Да, но не стоит только забывать, что std::remove_pointer применим не только к указателям, а вообще к любым типам. Между тем, ТС собирается применять это к алиасам типов, для которых не известно, является ли данный тип указателем, или чем-то другим. Возможно, имело бы смысл определить собственную метафункцию, во избежание "сюрпризов". Ну хотя бы так:


Можно проще:

template <typename T>
using MySpecialRemovePointer = std::enable_if<std::is_pointer<T>::value, std::remove_pointer_t<T>>;


--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 28.06.2018 6:34 rg45 . Предыдущая версия .
Re[5]: Как получить тип по указателю на него?
От: Кодт Россия  
Дата: 28.06.18 09:21
Оценка:
Здравствуйте, LazyKarlson, Вы писали:

LK>Оно да, но там надо пару ключей считать. Для этого ни ATL подключать, ни дополнительную структуру создавать не хотелось.

LK>А вот вывод указателя из Deleter::pointer был для меня откровением. Спасибо!

Так и этак придётся новую структуру писать
— либо удалятор для типа, причём, не являющегося Nullable Pointer, и потому формально не подходящего для хранения в unique_ptr,
— либо умный хэндл с необходимым минимумом стандартных методов
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.