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

使用带有限可变参数的模板函数限制允许的COM接口(std::is_same),com,c++17,variadic-templates,sfinae,fold-expression,Com,C++17,Variadic Templates,Sfinae,Fold Expression,我有包装类,包含指向不同接口的COM指针(或智能指针) 意愿: 一些COM类可以从其他各种COM接口获得,我想用可变类型创建一个模板构造函数,它只允许传递适当类型的参数 比如: template <class T, class = typename std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types> class WithCOMptrbase {

我有包装类,包含指向不同接口的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
};
模板
使用comptrbase初始化
{
受保护的:
T*ptr;
公众:
//通过复制构造智能指针
带comptrbase(T*ptr,bool AddRef=false)
:ptr_(ptr)
{
if(AddRef)ptr_u2;->AddRef();
}
/*通过从的参数查询接口来构造智能指针
与变量之一相同的类型*/
模板/*需要有一个合适的版本*/
带COMPTRBASE(类型其他*ptr)
:ptr(cQueryInterface(ptr))
{}
//其他方法
};
辅助功能:

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;
}
模板
T*cQueryInterface(U*ptr)
{
T*out;
HRESULT hr=ptr->QueryInterface(uu uuidof(T),(void**)和out);
如果(!succeed(hr))抛出错误(hr);
返回;
}
因此,我将定义我的包装器类

class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
{
   //methods
};
类包装器类:用comptrbase保护
{
//方法
};
到目前为止,我发现了以下线索: 但它只是关于结构,而不是函数。 我的目标是限制传递不适当的接口指针的可能性,因此不在运行时处理错误的接口错误

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

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);
}
模板
//为相同接口复制构造智能指针
WComPtr WFilterSame(常数WComPtr&pOther)
{
返回WComPtr(pOther);
}
模板
//如果不同,则查询接口
WComPtr WFilterSame(常数WComPtr&pOther)
{
return pOther.QueryInterface();
}
模板
WComPtr wfiltercominertrfptr(常数WComPtr&pOther)
{
静态断言(std::is_same::value)||
(std::is_same::value | |…),
“不支持接口。”);
返回WFilterSame(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
};
class-WComClass
{
私人:
WComPtr pComPtr_;//我的智能COM指针
模板
WComPtr WFilter(常数WComPtr&pOther)
{
返回WFilterComInterfPtr(波特);
}
公众:
模板
WComClass(const WComPtr&pOther)
:pComPtr_WFilter(pOther))
{}
//方法
};
到目前为止,它的行为符合预期(wfiltercominerfptr),我不希望它在包装类构造函数中失败

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


是否在变量列表之后通过默认类型查找

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
};
模板
类Impl
{
公众:
Impl()=默认值;
显式Impl(T*){static_cast(this)->ptr_queryinterface(ptr);}
};
模板
使用comptrbase初始化:私有Impl。。。
{
静态断言(std::是::值的基础);
静态断言((std::is \ u base \ u of::value&&…);
模板友元结构Impl;//我们没有可变友元:/
受保护的:
T*ptr_u2;=nullptr;
公众:
使用Impl::Impl。。。;
//通过复制构造智能指针
显式WithCOMptrbase(T*ptr,bool AddRef=false):ptr(ptr)
{
if(AddRef)ptr_u2;->AddRef();
}
//其他方法
};

除非限制C++的版本,否则我们将假定在这一点。尤其是因为它使问题更容易解决。:)第二,你的解决方案出了什么问题?
with comptrbase
中出现语法错误?您希望存储的TypeOther支持所有接口还是其中一个接口?一个似乎很奇怪。啊,您只希望允许
T
或'Types…`的poitner,然后您希望始终将其存储为
T
?有点像一个变体,但无法返回到存储的类型。@Yakk AdamNevraumont我想支持所有提供的接口。@Yakk AdamNevraumont,其想法是只允许传递提供的接口,因此在我的情况下,我只能在“I是,IInterface1,IInterface2,IInterface3”时使用comptrbase进行构造类型作为参数传递。现在,我成功地使用那些允许的TYE进行编译,并获得其他(不允许的)接口的编译错误。
(std::is_same_v | | |…)
替换
class=std::enable_if_t
允许多个ctor重载。另外,您的
..
太多,请尝试
std::enable_if_t=true
@PiotrSkotnicki-Ops。。。未看到
类型之后的类型
;谢谢。@max66想象一下,他们添加了第二个构造函数,它接受一个模板
T*
和一个SFINAE“test”子句。这种设计与恼人的错误信息相冲突;对于
,bool>=true
的设计,他们没有。我只是建议使用更好的默认SFINAE“cargo cult”技巧,以避免在任何给定情况下可能适用或可能不适用的潜在问题。@max66上次我检查时,
void*
不是有效的非类型模板参数类型,但我可以想象情况已经发生了变化。我是否正确理解:在您的情况下,您将生成所有可能的重载构造函数,而不是像另一个答案中的模板那样“按需”生成它们?是的,这就是目标。我得到错误C3203:“非专用类模板不能用作模板参数的模板参数”。对于带有“static_assert((std::is_base_of::value&&…);”的行,我还得到了“syntax error:'…”@谢尔盖·科莱斯尼克:我修正了一些打字错误。
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
};