接受函数指针的方法上的变分模板

Variadic Templates on Method Accepting Function Pointer

本文关键字:方法 函数 指针      更新时间:2023-10-16

在我看来,下面的代码应该可以正常工作,但它会产生

C2738: could not deduce template argument for 'Type'.

在VS2013中。

template <typename ReturnType, typename...Args>
uint GetParameterSize(ReturnType(*method)(Args...))
{
    return ParameterSize<Args...>();
}
template <typename Type, typename...Remaining>
uint ParameterSize()
{
    uint output = sizeof(Type);
    if (sizeof...(Remaining) > 0)
    {
        output += ParameterSize<Remaining...>();
    }
    return output;
}
void MyMethod3(int a, char b, int c )
{
}
// Elsewhere
uint size = GetParameterSize(&MyMethod3);

我想,"哦,也许是因为它没有最终条件。"所以我补充道:

template <typename Type>
uint ParameterSize()
{
    return sizeof(Type);
}

导致

C2668: 'ParameterSize' ambiguous call to overloaded function.

我的意思是,它看起来很简单,我认为它应该起作用。编译器怎么能不推导这些参数呢?我是一个新的可变模板,所以我可能会错过一些东西,但一些帮助将不胜感激。谢谢

  if (sizeof...(Remaining) > 0)
    {
        output += ParameterSize<Remaining...>();
    }

问题是,上面的代码是运行时检查,而不是编译时。因此,即使一旦Remaining的长度为0,它仍然必须编译ParamaterSize<>()的签名,即使它永远不会被执行。

对于这类问题,您实际上可以在编译时执行所有操作。

template<typename ... Args>
struct ParameterSize;   
{
   static const uint value = 0;
};
template<typename Type, typename... Remain>
struct ParameterSize<Type, Remain...>
{
   static const uint value = sizeof(Type) + ParameterSize<Remain...>::value;
};
template <typename ReturnType, typename...Args>
uint GetParameterSize(ReturnType(*method)(Args...))
{
    return ParameterSize<Args...>::value;
}

示例位于http://ideone.com/6aYRzI

我能想到的最简单的修复方法是调用过载解析:

template <typename Type>
constexpr unsigned ParameterSize(int)
{
    return sizeof(Type);
}
template <typename Type, typename...Remaining>
constexpr unsigned ParameterSize(...)
{
    return sizeof(Type) + ParameterSize<Remaining...>(42);
}
template <typename ReturnType, typename...Args>
constexpr unsigned GetParameterSize(ReturnType(*method)(Args...))
{
    return ParameterSize<Args...>(42);
}
void MyMethod3(int a, char b, int c )
{
}
int main()
{
    // Elsewhere
    unsigned size = GetParameterSize(&MyMethod3);
}

对于类型为int(如42)的参数,省略号使第二个重载比第一个重载匹配得更差,这就是解决歧义(ParameterSize<one_argument>(42))的方法。

对于您的代码不起作用的原因还有其他答案,所以我会给您一个替代方案。由于您似乎在累积sizeof(Type)以获得存储函数参数所需的总堆栈大小,因此我将如何做到这一点:

    #include <iostream>
    #include <algorithm>
    template <class ... Args>
    unsigned ParameterSize()
    {
        unsigned sizes[sizeof...(Args)] = {sizeof(Args)...};
        return std::accumulate(std::begin(sizes), std::end(sizes), 0);
    }
    template <typename ReturnType, typename...Args>
    uint GetParameterSize(ReturnType(*method)(Args...))
    {
        return ParameterSize<Args...>();
    }
    void MyMethod(int,int,int){}
    int main()
    {
        std::cout << GetParameterSize(&MyMethod) << std::endl;
    }

由于您的示例中已经有了运行时代码,我假设您不介意在运行时完成一些工作。