在此示例中,函数被传递给隐式实例化的函数模板。
// Function that will be passed as argument
int foo() { return 0; }
// Function template to call passed function
template<typename F>
int call(F f) {
return f();
}
template<typename F, typename A>
int call(F f, A a) {
return f(a);
}
int a = call(foo);
我们可以通过添加重载来破坏这段代码foo()
.
int foo(int i) { return 0; }
名字 ”foo
" 现在不明确,该示例将不再编译。可以通过显式提供函数指针类型信息来进行编译。
int (*func_takes_void)() = foo;
int a = call(func_takes_void);
int (*func_takes_int)(int) = foo;
int b = call(func_takes_int, 0);
http://coliru.stacked-crooked.com/a/e08caf6a0ac1e6b9
是否可以推导函数指针类型?如果是这样,为什么我的下面的尝试不起作用以及正确的方法是什么?
如果这是不可能的,一个好的答案可以解释原因。
迄今为止的尝试
人类可以看到哪个foo()
通过检查定义来在这两个调用中意在call<>()
但编译器无法使用该信息来进行重载解析。尽管如此,信息都在那里,只需将其拉入函数模板签名即可。这对于表达式 SFINAE 来说是可能的。
在伪代码中我们想要这样:
template<IgnoreThis, typename ReturnType>
struct expr_check
{
typedef ReturnType type;
}
template<typename F>
expr_check<expression requiring F have correct signature, result_of<F>::type>::type
call(F f);
这是在实际代码中实现的想法。
http://coliru.stacked-crooked.com/a/a3ce828d6cb16c2d
函数模板签名是:
template<typename F>
typename expr_check<sizeof(declval<F>()()), typename func_ptr_result<F>::type>::type
call(F f);
template<typename F, typename A>
typename expr_check<sizeof(declval<F>()(declval<A>())), typename func_ptr_result<F>::type>::type
call(F f, A a);
我目前拥有的内容无法编译。从编译器输出中,您可以看到在两次尝试实例化函数模板时,其中一次尝试都出现替换失败call<>()
重载,另一个只是给出一个不透明的“无法推断模板参数”。
(大肠虫被编译为 C++03,但 C++11 的答案很好。)
我怀疑在实例化时call<>()
, foo()
没有被调用,C++ 根本不提供重载解析foo()
在此背景下。可以证明这一点并不重要foo()
重载是正确的,C++ 只是在这里不强制要求重载解析。另一方面,重载解析并不限于正在调用的函数。适当类型的函数指针可以选择重载foo()
.
相关问题
有几个问题询问有关函数指针类型重载的问题。看来这个是做不到的。我没有发现任何试图通过表达式 SFINAE 执行此操作的问题。
这似乎是最接近的相关问题。
有没有办法推断函数指针模板参数的值?
额外的迂腐
标题中使用的“函数指针”是正确的短语吗? “函数参考”会更准确吗?