给定下面两个函数模板:
template <typename T>
void gorp(T*, std::function<void(T*)>)
{
}
template <typename T>
void klop(T*, std::function<void()>)
{
}
函数klop()
如我期望的那样工作,但gorp()
没有:
int x = 3;
//fails: candidate template ignored: could not match
//'function<void (type-parameter-0-0 *)>' against '(lambda at ...)
gorp( &x, [](int*){}); //1
//works
gorp<int>( &x, [](int*){}); //2
//fails: candidate template ignored: could not match
//'function<void (type-parameter-0-0 *)>' against 'void (^)(int *)'
gorp( &x, ^(int*){}); //3
//works
gorp<int>( &x, ^(int*){}); //4
//works
klop( &x, [](){}); //5
//works
klop( &x, ^(){}); //6
第3、4、6行使用clang块;第1、2、5行使用lambdas
注意到对klop()
的调用在推断T
时没有问题,但是我必须帮助对gorp()
的调用。
我很茫然。难道gorp()
不应该更容易找到T
吗?
如果必须使用std::function
,则可以禁止此参数的类型演绎:
template<typename T>
void gorp (T* t, std::function<void(std::type_identity_t<T*>)> func);
int x;
gorp(&x, [](int*){}); // works
但是我推荐
template <typename T, typename F>
void gorp(T* t, F&& f) requires(requires {f(t);})
{
f(t);
}
它接受前一个版本接受的所有内容,甚至更多,并且在不转换为std::function
的情况下更有效。
它不会推断类型T
,因为您没有传递std::function
。如果还需要转换,则类型推断不起作用。
gorp(&x, std::function<void(int*)>([](int*) {}));
使用普通函数指针也是如此:
template <typename T>
void gorp(T*, void(*)(T*))
{
}
gorp(&x, +[](int*) {}); // + converts captureless lambda to function pointer
或者支持Clang "blocks"
template <typename T>
void gorp(T*, void(^)(T*))
{
}
最后,用一个定义支持上述所有功能:
template <typename T, typename F>
void gorp(T*, F&& f)
{
}
如果函数被多次调用,这可能比使用std::function
定义更有效,因为std::function
确实会带来一些开销。