c++ - 函数模板中的参数包可以后跟另一个取决于返回类型的参数吗?
问题描述
我有一个函数,其中模板类型参数跟随参数包。它看起来像这样:
template<typename...Args, typename T>
T* default_factory_func()
{
return new T;
}
Visual C++ 编译器以错误拒绝它C3547: template parameter 'T' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'default_factory_func'
。
但是,我尝试了 Compiler Explorer 上可用的各种版本的 GCC(从 4.4.7 开始)和 clang(从 3.1 开始),它们都可以很好地编译此类代码。
// this code is just a minimal example condensed
// from a much more complex codebase
template<typename T>
T* construct(T* (*factory_func)())
{
return factory_func();
}
template<typename...Args, typename T>
T* default_factory_func() // C3547 on this line
{
return new T(Args()...);
}
struct some_class {
some_class(int, int, int) {}
};
int main()
{
construct<some_class>(
default_factory_func<int,int,int>
);
}
这是 MSVC 的一些怪癖还是标准不允许?
解决方案
我认为这里的标准很混乱(如果尚不存在,可能需要一个问题)。
- 根据[temp.param]的定义
default_factory_func
不正确
函数模板的模板形参包后面不应有另一个模板形参,除非该模板形参可以从函数模板的形参类型列表 ([dcl.fct]) 推导出来或具有默认实参
- 同时,
default_factory_func
可以(可以说)根据[temp.deduct.funcaddr]推断出的类型,因为您试图匹配通过some_class*(*)(void)
时的目标类型&default_factory_func<int,int,int>
模板参数可以从获取重载集地址时指定的类型推导出来。如果有目标,则将函数模板的函数类型和目标类型作为P和A的类型,按照[temp.deduct.type]中的描述进行推演。否则,对类型 P 和 A 的空集进行推导
我认为最安全的选择是通过重新排序模板参数来避免违反第一条规则:
template<class T, typename...Args>
T* default_factory_func()
{
return new T(Args()...);
}
然后显式地转换你的函数指针来解决重载:
auto foo = construct(
static_cast<some_class*(*)()>(default_factory_func<some_class, int, int, int>)
);
实时代码
(在 gcc/clang/和 msvc 上编译最新)
推荐阅读
- android - 如何检查我们的项目中是否存在反射api-Android工作室
- sonarqube - 用于 MSBuild 的 SonarQube 未报告质量问题
- javascript - 在 d3 错误中绘制一条线
- c# - CefSharp如何重命名和嵌入BrowserSubProcess.exe
- typescript - Typescript 3.0.1 无法理解嵌套的 reduce(s)
- json - 在 Svelte 的 main.js 中导入本地 json
- node.js - 如何在 TypeScript(main.ts) Angular 中创建 lowdb?
- javascript - 从打字稿类中的javascript文件导入代码
- angular - Angular 2/4/5/6 [(ngModel)] 后退按钮上未选中单选按钮
- python - 使用 keras 在情感分析中获得奇怪的准确性