为什么无法在此C++函数模板中推断模板类型?



给定下面两个函数模板:

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确实会带来一些开销。

相关内容

  • 没有找到相关文章

最新更新