我刚刚在Microsoft Connect上提交了关于无法编译以下玩具代码段的错误:
template <typename... P> struct S {
template <void(*F)(P...)> static void T() { }
};
void A(int, float) { }
int main() { S<int, float>::T<&A>(); }
Run Code Online (Sandbox Code Playgroud)
错误是:
test.cpp(2): error C3520: 'P' : parameter pack must be expanded in this context
Run Code Online (Sandbox Code Playgroud)
本质上,当用作模板参数时,我无法在函数签名内解压缩可变参数类型.这段代码(我认为)合法; 至少,GCC 4.7,Clang 3.0和ICC 13都支持它.
我已经看到了这个问题,但没有要求或给出变通方法,这正是我正在寻找的.
虽然不是超级关键(显然我多年来一直没有变量模板)但这种模式对于我想做的一些工作以及我想在C++上做的一些文章特别重要.用于序列化,脚本绑定等的11种反射技术,这是我想对Visual Studio用户有用的东西(因为它是迄今为止我所在行业中主要的编译器工具集).我希望微软的工程师能够在2013年RTM之前解决这个问题,但我并没有屏住呼吸.
一个玩具(这次来自内存)如何使用它的样本(减去使它稍微容易使用的宏):
Reflect<MyType>("MyType")
.bind("GetMatrix", mat44, &MyType::GetMatrix>()
.bind("Display", void, &MyType::Display>();
Run Code Online (Sandbox Code Playgroud)
当然,这可以在没有可变参数模板的情况下完成.当然,它只需要大量代码并接受对绑定成员函数的最大优点的限制.是的,将函数作为模板参数传递是重要的,因为成员函数指针在Visual Studio中的工作方式(可变大小)以及与不可能快速的C++代表(在我的C++社区,这种级别的优化有时实际上很重要),否定了使用std::function或类似设计的选择.
这个VS错误有解决办法吗?或者使用可变参数模板在VC++ 12中使用(编译时)函数指针参数的任何其他方法?
不知道为什么,但使用typedef进行简化似乎有效:
template <typename... P>
struct S
{
typedef void (*MyFunc)(P...);
template <MyFunc myFunc>
static void foo() {}
};
void foo2(int, float) {}
int main()
{
S<int, float>::foo<&foo2>();
}
Run Code Online (Sandbox Code Playgroud)
至少在Visual Studio 2013 Ultimate Preview上.