模板特化的 C++ 类型推导在 void 参数上失败
C++ Type deduction on template specialization fails on void parameter
我创建了一个模板 class,其中构造函数采用 std::function 对象。
第一个模板参数指示该函数的 return 值。
第二个参数定义了该函数的参数类型。
#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 时,请参阅 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 使用类型推导而不需要传递模板参数?
谢谢
int(void)
仅在狭窄的情况下用作 int()
。
改成这样:
template<class R, class... Args>
class Executor
并在正文中将 Arg
替换为 Args...
。
取消 R, void
专业化。
如果你需要 class Executor<void, Arg>
使用 class Executor<void, Args...>
.
您的代码现在将编译成作品。
(为什么会出现错误:隐式生成的演绎指南仅基于主要专业化。std::function(testSpecialization2)
是 std::function<int()>
,它与主要专业化的任何构造函数都不匹配。)
当你使用名称 Executor
而没有像 Executor<int, float>
中那样的显式模板参数时,C++ 通常会尝试弄清楚 class template argument deduction(或 CTAD)的含义。此过程不查看任何 class 模板专业化(部分或显式),仅查看主模板。
主模板具有构造函数 Executor(std::function<R(Arg)> function);
。这足以确定类型为 std::function<int(float)>
和 std::function<void(float)>
的参数的 R
和 Arg
。这只是为了确定 R
和 Arg
对于 Executor
是什么,然后应用专业化的正常考虑,所以第二个对象确实使用了 Executor<void, Arg>
专业化。
但是在看到 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>
。
看到它工作 on coliru。
我创建了一个模板 class,其中构造函数采用 std::function 对象。 第一个模板参数指示该函数的 return 值。 第二个参数定义了该函数的参数类型。
#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
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 使用类型推导而不需要传递模板参数?
谢谢
int(void)
仅在狭窄的情况下用作 int()
。
改成这样:
template<class R, class... Args>
class Executor
并在正文中将 Arg
替换为 Args...
。
取消 R, void
专业化。
如果你需要 class Executor<void, Arg>
使用 class Executor<void, Args...>
.
您的代码现在将编译成作品。
(为什么会出现错误:隐式生成的演绎指南仅基于主要专业化。std::function(testSpecialization2)
是 std::function<int()>
,它与主要专业化的任何构造函数都不匹配。)
当你使用名称 Executor
而没有像 Executor<int, float>
中那样的显式模板参数时,C++ 通常会尝试弄清楚 class template argument deduction(或 CTAD)的含义。此过程不查看任何 class 模板专业化(部分或显式),仅查看主模板。
主模板具有构造函数 Executor(std::function<R(Arg)> function);
。这足以确定类型为 std::function<int(float)>
和 std::function<void(float)>
的参数的 R
和 Arg
。这只是为了确定 R
和 Arg
对于 Executor
是什么,然后应用专业化的正常考虑,所以第二个对象确实使用了 Executor<void, Arg>
专业化。
但是在看到 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>
。
看到它工作 on coliru。