无法获取 std::bind() 返回对象的 operator() 指针
Cannot get operator() pointer of std::bind() returned object
我需要提取函数对象参数的类型。
Lambda 使用 operator()
转换为闭包对象。 std::function
也得到了 operator()
。
所以,我可以获得指向 operator()
的指针以传递给另一个函数,这样:
template <typename F, typename T, typename R, typename ... Args>
void helper(F&, R (T::*)(Args...) const)
{
// do something with Args types
}
template <typename F>
void bar(F f)
{
helper(f, &F::operator());
}
void freefunc(int) {}
void foo()
{
// lambda: ok
bar([](int){});
// std::function: ok
const std::function<void(double)> f = [](double){};
bar(f);
// std::bind: does not compile
auto g = std::bind(freefunc, std::placeholders::_1);
bar(g);
}
std::bind
也应该用 operator()
创建一个对象。但是,我的代码不适用于 std::bind()
,我不明白为什么。
gcc 产生此错误:
In instantiation of 'void bar(F) [with F = std::_Bind<void (*(std::_Placeholder<1>))(int)>]':
<source>:58:8: required from here
<source>:47:11: error: no matching function for call to 'helper(std::_Bind<void (*(std::_Placeholder<1>))(int)>&, <unresolved overloaded function type>)'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
<source>:39:6: note: candidate: 'template<class F, class T, class R, class ... Args> void helper(F&, R (T::*)(Args ...) const)'
39 | void helper(F&, R (T::*)(Args...) const)
| ^~~~~~
<source>:39:6: note: template argument deduction/substitution failed:
<source>:47:11: note: couldn't deduce template parameter 'T'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
ASM generation compiler returned: 1
<source>: In instantiation of 'void bar(F) [with F = std::_Bind<void (*(std::_Placeholder<1>))(int)>]':
<source>:58:8: required from here
<source>:47:11: error: no matching function for call to 'helper(std::_Bind<void (*(std::_Placeholder<1>))(int)>&, <unresolved overloaded function type>)'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
<source>:39:6: note: candidate: 'template<class F, class T, class R, class ... Args> void helper(F&, R (T::*)(Args ...) const)'
39 | void helper(F&, R (T::*)(Args...) const)
| ^~~~~~
<source>:39:6: note: template argument deduction/substitution failed:
<source>:47:11: note: couldn't deduce template parameter 'T'
47 | helper(f, &F::operator());
对 std::bind
执行相同操作的正确方法是什么?
不幸的是,你想做的事情是不可能的,因为 std::bind
的 return 类型在标准中规定得太松散了。
std::function::operator()
是标准明确定义的,所以你可以将它与 R (T::*)(Args... )
进行匹配,参见 [func.wrap.func.general],
- 对于 lambda 函数,[expr.prim.lambda.closure#3] 不是很清楚,但我认为它应该可以工作,
- 对于
std::bind
,规范 [func.bind.bind#4] 更广泛,因为它只说您可以调用 g(u1, u2, …, uM)
,其中 g
是 returned 值来自 std::bind
,因此无法保证 std::bind
的 return 类型甚至具有 operator()
成员函数。
这里的实际实现问题,对于 gcc、clang 和 msvc 都是一样的,是 return 值的 operator()
成员函数实际上是一个模板,所以你不能使用&F::operator()
直接 — 您不能获取模板化(成员)函数的地址。
简而言之 - 您不能为 std::bind
这样做,或者至少无法保证。尽管 std::bind
的结果是类似闭包的,但它是完全不同的。考虑一下如果下面 class 的内容是 std::bind
:
的结果会发生什么
class bind_result {
template<class T, class U>
U operator()(const T&);
private:
// implementation details
};
确实,您的函数 g
不会像那样对 class 起作用,因为 operator()
是一个模板。
我需要提取函数对象参数的类型。
Lambda 使用 operator()
转换为闭包对象。 std::function
也得到了 operator()
。
所以,我可以获得指向 operator()
的指针以传递给另一个函数,这样:
template <typename F, typename T, typename R, typename ... Args>
void helper(F&, R (T::*)(Args...) const)
{
// do something with Args types
}
template <typename F>
void bar(F f)
{
helper(f, &F::operator());
}
void freefunc(int) {}
void foo()
{
// lambda: ok
bar([](int){});
// std::function: ok
const std::function<void(double)> f = [](double){};
bar(f);
// std::bind: does not compile
auto g = std::bind(freefunc, std::placeholders::_1);
bar(g);
}
std::bind
也应该用 operator()
创建一个对象。但是,我的代码不适用于 std::bind()
,我不明白为什么。
gcc 产生此错误:
In instantiation of 'void bar(F) [with F = std::_Bind<void (*(std::_Placeholder<1>))(int)>]':
<source>:58:8: required from here
<source>:47:11: error: no matching function for call to 'helper(std::_Bind<void (*(std::_Placeholder<1>))(int)>&, <unresolved overloaded function type>)'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
<source>:39:6: note: candidate: 'template<class F, class T, class R, class ... Args> void helper(F&, R (T::*)(Args ...) const)'
39 | void helper(F&, R (T::*)(Args...) const)
| ^~~~~~
<source>:39:6: note: template argument deduction/substitution failed:
<source>:47:11: note: couldn't deduce template parameter 'T'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
ASM generation compiler returned: 1
<source>: In instantiation of 'void bar(F) [with F = std::_Bind<void (*(std::_Placeholder<1>))(int)>]':
<source>:58:8: required from here
<source>:47:11: error: no matching function for call to 'helper(std::_Bind<void (*(std::_Placeholder<1>))(int)>&, <unresolved overloaded function type>)'
47 | helper(f, &F::operator());
| ~~~~~~^~~~~~~~~~~~~~~~~~~
<source>:39:6: note: candidate: 'template<class F, class T, class R, class ... Args> void helper(F&, R (T::*)(Args ...) const)'
39 | void helper(F&, R (T::*)(Args...) const)
| ^~~~~~
<source>:39:6: note: template argument deduction/substitution failed:
<source>:47:11: note: couldn't deduce template parameter 'T'
47 | helper(f, &F::operator());
对 std::bind
执行相同操作的正确方法是什么?
不幸的是,你想做的事情是不可能的,因为 std::bind
的 return 类型在标准中规定得太松散了。
std::function::operator()
是标准明确定义的,所以你可以将它与R (T::*)(Args... )
进行匹配,参见 [func.wrap.func.general],- 对于 lambda 函数,[expr.prim.lambda.closure#3] 不是很清楚,但我认为它应该可以工作,
- 对于
std::bind
,规范 [func.bind.bind#4] 更广泛,因为它只说您可以调用g(u1, u2, …, uM)
,其中g
是 returned 值来自std::bind
,因此无法保证std::bind
的 return 类型甚至具有operator()
成员函数。
这里的实际实现问题,对于 gcc、clang 和 msvc 都是一样的,是 return 值的 operator()
成员函数实际上是一个模板,所以你不能使用&F::operator()
直接 — 您不能获取模板化(成员)函数的地址。
简而言之 - 您不能为 std::bind
这样做,或者至少无法保证。尽管 std::bind
的结果是类似闭包的,但它是完全不同的。考虑一下如果下面 class 的内容是 std::bind
:
class bind_result {
template<class T, class U>
U operator()(const T&);
private:
// implementation details
};
确实,您的函数 g
不会像那样对 class 起作用,因为 operator()
是一个模板。