Мне пришлось решать эту проблему не так давно, и я предложил два разных решения:
Первым был простой упаковщик, который инкапсулировал указатель с возможностью записи и мог иметь значение * 1003.* D в мой умный указатель.Это немного удобнее, чем использование временных указателей, о которых вы упоминаете, поскольку вы не можете определить тип непосредственно на сайте вызова.
Поэтому я не придерживался этого.Так что я сделал вспомогательную функцию Retrieve
, которая получала бы функцию COM и возвращала бы мой smart-указатель (и выполнял всю работу с временным указателем внутри).Теперь это тривиально работает со свободными функциями, которые имеют только один параметр T**
.Если вы хотите использовать это для чего-то более сложного, вы можете просто передать вызов через std::bind
и оставить только указатель, который будет возвращен, свободным.
Я знаю, что это не то, что выВы спрашиваете, но я думаю, что это аккуратное решение вашей проблемы.
В качестве примечания, я бы предпочел повысить intrusive_ptr в Boost вместо std :: unique_ptr, но это дело вкуса,как всегда.
Редактировать: Вот пример кода, который был перенесен из моей версии с использованием boost :: intrusive_ptr (поэтому он может не работать "из коробки" с unique_ptr)
template <class T, class PtrType, class PtrDel>
HRESULT retrieve(T func, std::unique_ptr<PtrType, PtrDel>& ptr)
{
ElementType* raw_ptr=nullptr;
HRESULT result = func(&raw_ptr);
ptr.reset(raw_ptr);
return result;
}
Например, его можно использовать так:
std::unique_ptr<IFileDialog, ComDeleter> FileDialog;
/*...*/
using std::bind;
using namespace std::placeholders;
std::unique_ptr<IShellItem, ComDeleter> ShellItem;
HRESULT status = retrieve(bind(&IFileDialog::GetResult, FileDialog, _1), ShellItem);
Для бонусных баллов вы можете даже позволить retrieve
вернуть unique_ptr вместо того, чтобы брать его по ссылке.Функтор, который генерирует bind
, должен иметь сигнатуры typedef для получения типа указателя.Затем вы можете сгенерировать исключение, если получите плохой HRESULT
.