我有以下示例,其中包含两个版本的 make 函数,它们接受另一个函数并推导参数类型。然后它使用该函数创建模板化 Signature 类型的结构。
enum class SomeEnum {
ONE = 1,
TWO = 2,
};
template <SomeEnum _Type, typename _Result, typename... _Args>
struct Signature {
static constexpr SomeEnum Type = _Type;
using Result = _Result;
using Args = std::tuple<_Args...>;
std::function<_Result (_Args...)> func;
};
template <
SomeEnum _Type,
typename _Result,
typename... _Args>
Signature<_Type, _Result, _Args...> make(
std::function<_Result (_Args...)> func) {
return Signature<_Type, _Result, _Args...>{.func = func};
}
template <SomeEnum _Type, typename _Result, typename... _Args>
Signature<_Type, _Result, _Args...> make(
_Result (*func)(_Args...)) {
return Signature<_Type, _Result, _Args...>{
.func = std::move(func)};
}
void foo(int x, std::string y, int z) {
}
auto sig1 = make<SomeEnum::ONE>(&foo);
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
此版本有效:
auto sig1 = make<SomeEnum::ONE>(&foo);
但是这个版本:
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
没有
main.cpp:40:13: error: no matching function for call to 'make'
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
^~~~~~~~~~~~~~~~~~~
main.cpp:23:37: note: candidate template ignored: could not match 'std::function<_Result (_Args...)>' against '(lambda at main.cpp:40:33)'
Signature<_Type, _Result, _Args...> make(
^
main.cpp:29:37: note: candidate template ignored: could not match '_Result (*)(_Args...)' against '(lambda at main.cpp:40:33)'
Signature<_Type, _Result, _Args...> make(
^
1 error generated.
但是,如果我明确设置类型,那么它就可以工作:
std::function<void(int x, std::string y, int z)> l = [](int x, std::string y, int z) {
};
auto sig2 = make<SomeEnum::TWO>(l);
我怎样才能制作这个版本:
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
工作?我希望能够通过额外的输入来传递 lambda,并让代码推导出类型。
std::function
支持 CTAD(通过其推导指南),但 CTAD 不适用于函数参数。
所以你的参数类型必须是模板化的(而不是
std::function<__>
):
template <typename F> void foo(F &&func) {bar(std::function(func));}
其中
bar
接受 std::function<R(P...)>
,就像您第一次重载 make()
。