c++ - 表达式 SFINAE 重载传递函数指针的类型

标签 c++ templates c++11 function-pointers sfinae

在这个例子中,一个函数被传递给一个隐式实例化的函数模板。

// 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<>() 都出现了替换失败。重载,另一个只是给出一个不透明的“无法推断模板参数”。

(colirus 被编译为 C++03,但 C++11 答案很好。)

我怀疑在实例化 call<>() 时, foo()没有被调用,C++ 根本不提供 foo() 的重载解析在这种情况下。可以证明一个 foo() 并不重要重载是正确的,C++ 只是在这里不强制执行重载解析。另一方面,重载解析不限于被调用的函数。适当类型的函数指针可以选择 foo() 的重载.

相关问题

有几个关于函数指针类型重载的问题。看起来这是做不到的。我没有发现任何试图通过表达式 SFINAE 执行此操作的问题。

这似乎是最相关的问题。

Is there a way to deduce the value of a function pointer template parameter?

额外学究

“函数指针”是标题中使用的正确短语吗? “功能引用”会更准确吗?

最佳答案

你能得到的最接近的可能是这样的:

struct sfoo
{
  template<typename... args>
  void operator() (args&&... a)
  { 
    foo(std::forward<args>(a)...);
  }
};

并传递 sfoo(或 sfoo())而不是 foo

即创建一个函数对象类型,将整个重载集封装在模板化的operator()中。

然后不是对不存在的模板参数进行重载解析,而是对同一参数进行模板实例化,这没问题。

关于c++ - 表达式 SFINAE 重载传递函数指针的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27523684/

相关文章:

c++ - 创建一个计算器 C++

c++ - 从 QT 中的 C++ 代码访问 QML 元素

C++11 regex_token_iterator

c++11 - 使用 unique_ptr 的 pimpl 惯用语中的 ABI

c++ - 从有限列表中简单选择

c++ - 段错误c++导致程序崩溃

c++ - 为什么这是 g++8 的非常数条件?

c++ - 避免具有继承的类之间重复 typedef

python - Django - 自定义模板标签传递关键字参数

c++ - i = i + 1 和++i 之间的速度比较