请考虑以下内容(doesn't compile,但稍后我们会修复):
void foo(const int *n) { }
template <typename ...Args>
void bar(void (*func)(Args...), Args... args) { func(args...); }
int main(int argc, char *argv[])
{
int n = 42;
bar(foo, &n);
}
模板函数bar()
使用要调用的函数指针和要传递给它的参数参数包。 gcc 7.4.0诊断以下错误:
test.cpp:6:6: note: template argument deduction/substitution failed:
test.cpp:11:16: note: inconsistent parameter pack deduction with ‘const int*’ and ‘int*’
很明显,type deduction rules不够放松,无法在同时观察到const T*
和const T*
时推论T*
。好的。这很容易fix with a cast:
bar(foo, static_cast<const int *>(&n));
但这很丑。 C ++ 17具有std::as_const()
,这使它看起来不那么丑陋(&std::as_const(n)
),但是在我当前的项目中,我仅限于使用C ++ 14,sadface。
Q :有没有一种方法可以重新排列此代码,以使类型推断成功完成而无需显式指定bar()
的模板参数,也无需进行强制转换即可解决模棱两可的常数性?只要我可以将函数指针及其参数传递给模板函数,就可以在框外进行思考!
答案 0 :(得分:5)
您可以将函数指针和参数的推论分开:
void foo(const int *n) {}
template <typename... FArgs, typename... Args>
void bar(void (*func)(FArgs...), Args&&... args) {
func(std::forward<Args>(args)...);
}
int main(int argc, char *argv[]) {
int n = 42;
bar(foo, &n);
}
但是到那时我不知道为什么要分解函数指针。为什么不接受任何可呼叫电话?
void foo(const int *n) {}
template <typename F, typename... Args>
void bar(F func, Args&&... args) {
func(std::forward<Args>(args)...);
}
int main(int argc, char *argv[]) {
int n = 42;
bar(foo, static_cast<const int *>(&n));
bar([](int const*){}, &n);
}
另外,请记住,C ++ 17提供了std::invoke
:
std::invoke(foo, &n);