c++ - void 参数上模板特化的 C++ 类型推导失败
问题描述
我创建了一个模板类,其中构造函数采用 std::function 对象。第一个模板参数表示该函数的返回值。第二个参数定义该函数的参数类型。
#include <functional>
//Base
template<class R, class Arg>
class Executor {
public:
Executor(std::function<R(Arg)> function)
: mFunction(function)
{}
private:
std::function<R(Arg)> mFunction;
};
//Specialization1
template<class Arg>
class Executor<void, Arg> {
public:
Executor(std::function<void(Arg)> function)
: mFunction(function)
{}
private:
std::function<void(Arg)> mFunction;
};
//Specialization2
template<class R>
class Executor<R, void> {
public:
Executor(std::function<R()> function)
: mFunction(function)
{}
private:
std::function<R()> mFunction;
};
int testBase(float value) {
return 5;
}
void testSpecialization1(float value) {}
int testSpecialization2() {
return 22;
}
int main() {
Executor executorBase{std::function(testBase)};
Executor executorSpecialization1{std::function(testSpecialization1)};
//Executor<int, void> executorSpecialization2{std::function(testSpecialization2)}; // Compiles
Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
}
在使用函数 std::function<int()> 时,请参阅 executorSpecialization2,编译器会抱怨:
main.cpp: In function 'int main()':
main.cpp:55:72: error: class template argument deduction failed:
55 | Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
| ^
main.cpp:55:72: error: no matching function for call to 'Executor(std::function<int()>)'
main.cpp:7:9: note: candidate: 'template<class R, class Arg> Executor(std::function<R(Arg)>)-> Executor<R, Arg>'
7 | Executor(std::function<R(Arg)> function)
| ^~~~~~~~
main.cpp:7:9: note: template argument deduction/substitution failed:
main.cpp:55:72: note: candidate expects 1 argument, 0 provided
55 | Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
| ^
main.cpp:5:7: note: candidate: 'template<class R, class Arg> Executor(Executor<R, Arg>)-> Executor<R, Arg>'
5 | class Executor {
| ^~~~~~~~
main.cpp:5:7: note: template argument deduction/substitution failed:
main.cpp:55:72: note: 'std::function<int()>' is not derived from 'Executor<R, Arg>'
55 | Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
|
它尝试使用基本版本。但当然缺少第二个参数。如果我指定它编译的模板参数。
那么为什么为 executorSpecialization2 选择基本模板呢?甚至可以在不需要传递模板参数的情况下对 void 使用类型推导吗?
谢谢
解决方案
当您使用Executor
没有像 in 这样的显式模板参数的名称时,C++ 通常会尝试通过类模板参数推导(或 CTAD)Executor<int, float>
来弄清楚您的意思。此过程不查看任何类模板特化(部分或显式),只查看主模板。
主模板具有构造函数Executor(std::function<R(Arg)> function);
。这足以确定R
和Arg
用于类型std::function<int(float)>
和的参数std::function<void(float)>
。这只是为了确定什么R
和Arg
用于Executor
,然后适用专业化的正常考虑,因此第二个对象确实使用了Executor<void, Arg>
专业化。
但是看到 type std::function<int()>
,那不匹配std::function<R(Arg)>
,所以 CTAD 失败。(虽然您可以拼写一个空函数参数列表,其(void)
含义与 相同()
,但这是一个需要非依赖void
类型的特殊规则,并且不适用于恰好具有类型的模板参数void
。)
但是您可以通过编写“演绎指南”来协助 CTAD:
template <class R>
Executor(std::function<R()>) -> Executor<R, void>;
除了主模板的构造函数之外,还使用了演绎指南。现在std::function<int()>
void 类型的参数与推导指南匹配,编译器确定R
应该是int
,并使用Executor<int, void>
,这是由第二个部分特化定义的。
看到它在 coliru 上工作。
推荐阅读
- reactjs - 具有样式、css 和 sass 加载器的 scss 文件的正确 webpack 配置是什么
- c# - 在restful api c#中处理位图
- jquery-terminal - 在尝试为我的投资组合网站构建自己的 Web 终端时,我遇到了 jquery-terminal 的一些问题
- java - 是否有 RecyclerView 的 OnScrollListener 在滚动时连续调用,而不仅仅是在状态更改或滚动开始时调用?
- reactjs - 如何在连接检查时显示等待指示器?
- vue.js - Vue / Vuetify - 在 a 中显示 v-select 文本值
- swift - 有什么方法可以在不闪烁或闪烁的情况下使用 MKUserLocation 移动 MKCircle 叠加层?
- linux - hcitool lescan 设置扫描参数失败:输入/输出错误
- python - 比较两组大型数据时,复杂性可以从 O(n^2) 降低到 O(n) 吗?
- javascript - 将 Vue.js 集成到现有 ASP.NET MVC5 项目中的最佳方式