探究类模板Bar构造函数传递函数的两种方式及编译问题
为什么带参数名的函数类型构造函数会报错?
咱们直接拆解这个问题的核心,你遇到的是旧版本编译器(GCC 5.4.0、Clang 3.8.0)在模板特化场景下的语法解析bug。
两种写法的本质差异
- 无参数名的构造函数
Bar( void(Args...) ):编译器能正确识别Args...是来自类模板特化Bar<void(Args...)>的参数包,这里的void(Args...)是明确的函数类型声明(函数声明中允许省略参数名),所以编译流程完全正常。 - 带参数名的
Bar( void(Args...) func ):旧编译器在这里出了错——它把void(Args...)里的Args...误判为C风格的可变参数(也就是void(...)那种不定参数),而不是你定义的模板参数包。这就导致编译器找不到Args的声明,直接抛出编译错误。
标准角度的合法性
其实从C++标准来说,void(Args...) func的写法本身是合规的:函数类型作为函数参数时,会被自动调整为对应的函数指针类型(等价于void(*func)(Args...))。但旧版本的GCC和Clang在处理模板参数包与函数类型参数的组合时,存在语法解析的歧义bug,才导致编译失败。
兼容旧编译器的解决办法
如果想在这些旧编译器中使用带参数名的写法,直接显式声明为函数指针类型就行:
Bar( void(*func)(Args...) ) // 这个版本能正常编译 { }
这样就明确告诉编译器你要的是函数指针,避开了它对函数类型参数的解析歧义。
内容的提问来源于stack exchange,提问作者Olumide
相关产品推荐
相关产品推荐

