代码之家  ›  专栏  ›  技术社区  ›  Sergey Kolesnik

使用带有限可变参数的模板函数限制允许的COM接口(std::is_same)

  •  2
  • Sergey Kolesnik  · 技术社区  · 7 年前

    我有包装类,包含指向不同接口的COM指针(或智能指针)。

    一些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
    };
    

    到目前为止,我发现了以下线索: How to make a variadic is_same? 但它只是关于结构,而不是函数。

    更新: 因为组合比继承更可取,所以我重新思考并决定使用模板函数而不是模板类。到目前为止,我已经成功地将给出的答案结合起来,并得出以下结论:

    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);
    }
    

    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
    };
    

    到目前为止,它的行为符合预期(wfiltercominerfptr),我不希望它在包装类构造函数中失败。

    2 回复  |  直到 7 年前
        1
  •  4
  •   max66    7 年前

    试一试

       template <class TypeOther, class =
          std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>        
          WithCOMptrbase(TypeOther* ptr)
            : ptr_(cQueryInterface<T>(ptr))
          {}
    

    我是说。。。您使用了三个省略号而不是一个(请在后面删除省略号) ::value Types )你还需要一对括号。

    template <class T, class ... Types, class = typename 
       std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
       class WithCOMptrbase
    

    ?

    通过默认类型输入 可变列表?

        2
  •  1
  •   Jarod42    7 年前

    CRTP如何避免某些模板:

    template <typename Base, typename T>
    class Impl
    {
    public:
        Impl() = default;
        explicit Impl(T*) { static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr); }
    };
    
    template <class T, class ... Ts>
    class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
    {
        static_assert(std::is_base_of<IUnknown, T>::value);
        static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
    
        template <typename, typename> friend struct Impl; // We don't have variadic friend :/
    protected:
        T* ptr_ = nullptr;
    
    
    public:
        using Impl<WithCOMptrbase, Ts>::Impl...;
    
        //construct smart pointer by copy
        explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
        {
            if (AddRef) ptr_->AddRef();
        }
    
        //other methods
    };