为什么在这个C++函数模板中不能推断模板类型?

ux6nzvsh  于 2023-04-08  发布在  其他
关注(0)|答案(2)|浏览(110)

给定以下两个函数模板:

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 blocks;第1、2、5行使用lambdas
请注意,对klop()的调用在推断T时没有问题,但我必须帮助解决对gorp()的调用。
我很困惑,gorp()计算T不是应该加倍容易吗?

cx6n0qe3

cx6n0qe31#

如果你必须有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

u7up0aaq

u7up0aaq2#

它不会推断类型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“块”:

template <typename T>
void gorp(T*, void(^)(T*))
{
}

最后,用一个定义来支持上述所有内容:

template <typename T, typename F>
void gorp(T*, F&& f)
{
}

如果函数被多次调用,这可能比使用std::function的定义更有效,因为std::function确实会带来一些开销。

相关问题