"模糊调用重载函数"在VS2013中使用可变参数模板时

时间:2014-07-21 21:26:07

标签: c++ c++11 templates visual-studio-2013 variadic-templates

给出以下代码:

        template <typename T>
        bool TryQueryInterface(
            IUnknown* in_toQuery,
            REFIID riid,
            void **ppvObject,
            ComObject* in_parent,
            HRESULT out_result)
        {
            if (InterfaceProperties<T>::GetIID() == riid)
            {
                void *underlying;
                HRESULT result = in_toQuery->QueryInterface(riid, &underlying);
                if (SUCCEEDED(result))
                {
                    *ppvObject = new typename InterfaceProperties<T>::WrapperClass(
                        *this,
                        (T*)underlying,
                        in_parent);
                }

                return true;
            }

            return false;
        }

        template <typename T, typename... Interfaces>
        bool TryQueryInterfaces(
            IUnknown* in_toQuery,
            REFIID riid,
            void **ppvObject,
            ComObject* in_parent,
            HRESULT out_result)
        {
            return TryQueryInterface<T>(in_toQuery, riid, ppvObject, in_parent, out_result) ||
                   TryQueryInterfaces<Interfaces...>(in_toQuery, riid, ppvObject, in_parent, out_result);
        }

        template <typename T>
        bool TryQueryInterfaces(
            IUnknown* in_toQuery,
            REFIID riid,
            void **ppvObject,
            ComObject* in_parent,
            HRESULT out_result)
        {
            return TryQueryInterface<T>(in_toQuery, riid, ppvObject, in_parent, out_result);
        }

我收到以下错误:

    error C2668: 'TryQueryInterfaces' : ambiguous call to overloaded function
TryQueryInterfaces<ITrusteeGroupAdmin>(IUnknown *,const IID &,void **,ComObject *,HRESULT)'
 or       TryQueryInterfaces<ITrusteeGroupAdmin,>(IUnknown *,const IID &,void **,ComObject *,HRESULT)'
          while trying to match the argument list '(IUnknown *, const IID, void **, ComObject *, HRESULT)'
see reference to function template instantiation 'bool TryQueryInterfaces<ITrusteeAdmin,ITrusteeGroupAdmin>(IUnknown *,const IID &,void **,ComObject *,HRESULT)' being compiled

我在这里缺少什么?如何为递归构造一个明确的基本案例?

4 个答案:

答案 0 :(得分:3)

这是不明确的,因为参数包Interfaces...可能为空。确保至少采用一个参数加上一些额外的(可能为零)参数。将第二种方法更改为:

template <typename T, typename Interface, typename... Interfaces>
bool TryQueryInterfaces(
    IUnknown* in_toQuery,
    REFIID riid,
    void **ppvObject,
    ComObject* in_parent,
    HRESULT out_result)
{
    return TryQueryInterface<T>(in_toQuery, riid, ppvObject, in_parent, out_result) ||
           TryQueryInterfaces<Interface, Interfaces...>(in_toQuery, riid, ppvObject, in_parent, out_result);
}

答案 1 :(得分:3)

使用可变参数模板重载函数与使用常规模板稍有不同。

你可以超载:

void foo()
{
}

template <typename Arg1, typename ...Args>
void foo()
{
}

但不是

template <typename Arg1>
void foo()
{
}

template <typename Arg1, typename ...Args>
void foo()
{
}

因为当有一个参数时,无法消除要调用的函数的歧义。

在您的情况下,您可以使用帮助程序类来处理调用。

// Forward declaration of the helper class and its template arguments.
template <typename ...Types> struct TryQueryInterfacesHelper;

// helper class with just one argument.
template <typename T>
struct TryQueryInterfacesHelper<T>
{
   bool operator()(IUnknown* in_toQuery,
                   REFIID riid,
                   void **ppvObject,
                   ComObject* in_parent,
                   HRESULT out_result)
   {
      return TryQueryInterface<T>(in_toQuery, riid, ppvObject, in_parent, out_result);
   }
};

// helper class with more than one argument.
template <typename T, typename ...Interfaces>
struct TryQueryInterfacesHelper<T, Interfaces...>
{
   bool operator()(IUnknown* in_toQuery,
                   REFIID riid,
                   void **ppvObject,
                   ComObject* in_parent,
                   HRESULT out_result)
   {
      return TryQueryInterface<T>(in_toQuery, riid, ppvObject, in_parent, out_result) ||
         TryQueryInterfacesHelper<Interfaces...>()(in_toQuery, riid, ppvObject, in_parent, out_result);
   }
};

template <typename... Interfaces>
bool TryQueryInterfaces(
      IUnknown* in_toQuery,
      REFIID riid,
      void **ppvObject,
      ComObject* in_parent,
      HRESULT out_result)
{
   // Implement the function using the helper class.
   return TryQueryInterfacesHelper<Interfaces...>()(in_toQuery, riid, ppvObject, in_parent, out_result);
}

这是一个用更简单的类和函数测试想法的示例程序。

#include <iostream>

template <class ...Types> struct X;

template <class T>
struct X<T>
{
   void operator()(){std::cout << "Came to X<T>\n";}
};

template <class T, class ...Types>
struct X<T, Types...> 
{
   void operator()(){std::cout << "Came to X<T, Types...>\n"; X<Types...>()();}
};

template <class ...Types>
void foo()
{
   X<Types...>()();
}

int main()
{
   foo<int>();
   foo<int, double>();
   foo<int, double, char>();
}

输出:

Came to X<T>
Came to X<T, Types...>
Came to X<T>
Came to X<T, Types...>
Came to X<T, Types...>
Came to X<T>

答案 2 :(得分:2)

另一个解决方案是使用enable_if仅在包非空时使用参数包启用TryQueryInterfaces实现。您还应该重新排列两个TryQueryInterfaces实现,以便处理单个模板参数的终端案例高于另一个。这允许参数包版本中的名称查找成功。

这也允许你摆脱TryQueryInterface实现。

template<typename T>
bool TryQueryInterfaces(IUnknown* in_toQuery,
                        REFIID riid,
                        void **ppvObject,
                        ComObject* in_parent,
                        HRESULT out_result)
{
    // query single interface here
}

template<typename T, typename... Interfaces>
typename std::enable_if<sizeof...(Interfaces) != 0, bool>::type
 TryQueryInterfaces(IUnknown* in_toQuery,
                    REFIID riid,
                    void **ppvObject,
                    ComObject* in_parent,
                    HRESULT out_result)
{
    return TryQueryInterfaces<T>(in_toQuery, riid, ppvObject, in_parent, out_result) || 
           TryQueryInterfaces<Interfaces...>(in_toQuery, riid, ppvObject, in_parent, out_result);
}

Live demo

答案 3 :(得分:0)

 template <typename T>
 void foo();

 template <typename T, template ...R>
 void foo();

两者都匹配foo<X>();

为了发挥一些作用,请使用两种类型:

 template <typename T1, typename T2, template ...R>
 void foo();