我正在尝试使用带有模板作为参数的函数指针。但是编译器似乎在处理lambda和nullptr时遇到问题。
当我在以下代码中将void (*callback)(T input)
更改为void (*callback)(int input)
时,一切都很好。
此编译器行为是否由C ++标准指定?
我使用的编译命令为$ g++ main.cpp -std=c+11
,但在Visual Studio 2019中具有相同的行为。
template <class T>
int dummy (T tmp, void (*callback)(T input)) {
// Doesn't do anything, just trying to compile
// If I change (T input) to (int input), it compiles fine
if (callback)
return 1;
else
return 0;
}
void callback (int input) {
return;
}
int main () {
int tmp = 10;
auto callback_lambda = [](int input) -> void {
return;
};
dummy(tmp, callback); // Compiles OK
dummy(tmp, callback_lambda); // Error: mismatched types 'void (*)(T)' and 'main()::<lambda(<int>)'
dummy(tmp, nullptr); // Error: no matching function for call to 'dummy(int&, std:nullptr_t)'
return 0;
}
答案 0 :(得分:6)
问题在于template argument deduction中不会考虑隐式转换。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是overload resolution的工作,以后会发生。
因此,当传递lambda和nullptr
时,不考虑对函数指针的转换,无法为第二个函数参数推导模板参数T
并导致错误。 / p>
您可以在non-deduced context的帮助下,将第二个功能参数设为std::type_identity
,以将其排除在推论之外。
type_identity
可用于阻止template argument deduction:
例如
template <class T>
int dummy (T tmp, void (*callback)(std::type_identity_t<T>)) {
...
}
PS:如果编译器不支持std::type_identity
(自C ++ 20起),则可以定义自己的版本,这并不困难。