У меня есть классы-обертки, соединяющие COM-указатели (или умные указатели) с различными интерфейсами.
INTEND:
Некоторые COM-классы могут быть получены из различных других COM-интерфейсов, и я хочу создать шаблонный конструктор с переменными типами, который позволял бы передавать аргументы только соответствующих типов.
что-то вроде:
template <class T, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types>
class WithCOMptrbase
{
protected:
T* ptr_;
public:
//construct smart pointer by copy
WithCOMptrbase(T* ptr, bool AddRef = false)
: ptr_(ptr)
{
if (AddRef) ptr_->AddRef();
}
/*construct a smart pointer by querying an interface from an argument of
a type which is the same as one of the variadics*/
template <class TypeOther, class = typename
std::enable_if<syd::is_same<Types... , TypeOther>::value... ||
...>::type> /*there needs to be a proper version*/
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
{}
//other methods
};
вспомогательная функция:
template <class U, class = typename
std::enable_if<std::is_base_of<IUnknown, U>::value>::type>
T* cQueryInterface<T>(U *ptr)
{
T* out;
HRESULT hr = ptr->QueryInterface(__uuidof(T), (void**)&out);
if (!SUCCEEED(hr)) throw _com_error(hr);
return out;
}
Поэтому я определю свой класс-оболочку
class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
{
//methods
};
Пока я нашел эту тему:
Как сделать variadic is_same?
но речь идет только о структурах, а не о функциях.
Моя цель состоит в том, чтобы ограничить возможность передачи неверного указателя интерфейса, чтобы не допускать неправильных ошибок интерфейса во время выполнения.
UPDATE:
Поскольку составление предпочтительнее наследования, я немного переосмыслил и решил использовать шаблонную функцию, а не шаблонный класс. До сих пор мне удалось объединить данные ответы и придумать это:
template <bool S, class Out, class Other, typename
std::enable_if<S>::type* = nullptr>
//copy-construct Smart Pointer for same Interfaces
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
{
return WComPtr<Out>(pOther);
}
template <bool S, class Out, class Other, typename
std::enable_if<!S>::type* = nullptr>
//Query Interface if differ
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
{
return pOther.QueryInterface<Out>();
}
template <class Out, class ... Permitted, class Other>
WComPtr<Out> WFilterComInterfPtr(const WComPtr<Other>& pOther)
{
static_assert(std::is_same<Out, Other>::value ||
(std::is_same<Permitted, Other>::value || ...),
"Interface is not supported.");
return WFilterSame<std::is_same<Out, Other>::value, Out>(pOther);
}
Теперь я могу определить конструктор моего класса оболочки COM:
class WComClass
{
private:
WComPtr<Interface> pComPtr_; //My Smart COM pointer
template <class Other>
WComPtr<Interface> WFilter(const WComPtr<Other>& pOther)
{
return WFilterComInterfPtr<Interface, IAllowed1, IAllowed2>(pOther);
}
public:
template <class Other>
WComClass(const WComPtr<Other>& pOther)
: pComPtr_(WFilter(pOther))
{}
//methods
};
Пока он ведет себя как задумано (WFilterComInterfPtr), я не ожидаю, что он потерпит неудачу в конструкторе класса-оболочки.