【发布时间】:2016-12-18 00:24:36
【问题描述】:
我想要一个std::function<void(char**)> 类型的变量。这是一个未能做到这一点的简单示例。
我想了解的是:
- 当我调用
jj_2a(5, 6)时,编译器没有 抱怨的 auto 是什么?该函数已绑定所有参数。 - 但如果我不使用 auto,我会得到我期望的行为(编译错误带有参数)。很明显,
function<void(void)>根本不是 auto 决定的。 - 如果我绑定第一个参数而不是第二个参数 (
jj_3),则使用两个参数调用(但根据我的心智模型会丢弃错误的参数)同时使用一个参数调用(我认为应该可以)无法编译。 - 将
std::functional用于jj_3_f表示“没有可行的转换”,尽管到目前为止错误消息对我没有帮助。
有关编译器和特定错误,请参见下文。这是linux,clang 3.8.0,ubuntu 16.04.1。
#include <functional>
#include <iostream>
void jj_1(int x, int y) { std::cout << x << ' ' << y << std::endl; }
int main() {
using namespace std::placeholders; // for _1, _2, _3...
auto jj_2a = std::bind(jj_1, 3, 2);
jj_2a(5, 6); // This works, prints "3 2", no compiler warning, is auto drunk?
jj_2a(); // This also works, prints "3 2".
std::function<void(void)> jj_2a_f = std::bind(jj_1, 30, 20);
//jj_2a_f(50, 60); // Compile error, good!
jj_2a_f(); // This works, prints "30 20", good!
auto jj_2b = std::bind(jj_1, _2, _1);
jj_2b(5, 6); // This works, prints "6 5", good.
auto jj_3 = std::bind(jj_1, 3, _2);
jj_3(5, 6); // This works, prints "3 6", so it's the first arg that is dropped!
//jj_3(7); // Compile error!
//std::function<void(int)> jj_3_f = std::bind(jj_1, 3, _2); // Compile error, no viable conversion!
//jj_4(11);
}
我用这个编译
clang++ -std=c++14 -Wall -Wextra /tmp/foo.cc -o /tmp/foo
与jj_3(7) 相关的编译器警告如下:
/tmp/foo.cc:21:7: error: no matching function for call to object of type 'std::_Bind<void (*(int,
std::_Placeholder<2>))(int, int)>'
jj_3(7); // Compile error!
^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:1129:2: note:
candidate template ignored: substitution failure [with _Args = <int>]: no viable conversion from
'std::_No_tuple_element' to 'int'
operator()(_Args&&... __args)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:1143:2: note:
candidate template ignored: substitution failure [with _Args = <int>]: no viable conversion from
'std::_No_tuple_element' to 'int'
operator()(_Args&&... __args) const
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:1157:2: note:
candidate template ignored: substitution failure [with _Args = <int>]: no viable conversion from
'std::_No_tuple_element' to 'int'
operator()(_Args&&... __args) volatile
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:1171:2: note:
candidate template ignored: substitution failure [with _Args = <int>]: no viable conversion from
'std::_No_tuple_element' to 'int'
operator()(_Args&&... __args) const volatile
^
1 error generated.
与jj_3_f 相关的编译器警告如下:
/tmp/foo.cc:23:32: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<void (&)(int,
int)>::value, void (&)(int, int), int, const _Placeholder<2> &>::type' (aka '_Bind<void (*(int,
std::_Placeholder<2>))(int, int)>') to 'std::function<void (int)>'
std::function<void(int)> jj_3_f = std::bind(jj_1, 3, _2); // Compile error, no viable conversion!
^ ~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:2008:7: note:
candidate constructor not viable: no known conversion from 'typename
_Bind_helper<__is_socketlike<void (&)(int, int)>::value, void (&)(int, int), int, const
_Placeholder<2> &>::type' (aka '_Bind<void (*(int, std::_Placeholder<2>))(int, int)>') to
'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:2019:7: note:
candidate constructor not viable: no known conversion from 'typename
_Bind_helper<__is_socketlike<void (&)(int, int)>::value, void (&)(int, int), int, const
_Placeholder<2> &>::type' (aka '_Bind<void (*(int, std::_Placeholder<2>))(int, int)>') to 'const
std::function<void (int)> &' for 1st argument
function(const function& __x);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:2028:7: note:
candidate constructor not viable: no known conversion from 'typename
_Bind_helper<__is_socketlike<void (&)(int, int)>::value, void (&)(int, int), int, const
_Placeholder<2> &>::type' (aka '_Bind<void (*(int, std::_Placeholder<2>))(int, int)>') to
'std::function<void (int)> &&' for 1st argument
function(function&& __x) : _Function_base()
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/functional:2054:2: note:
candidate template ignored: substitution failure [with _Functor = std::_Bind<void (*(int,
std::_Placeholder<2>))(int, int)>, $1 = void]: no type named 'type' in
'std::result_of<std::_Bind<void (*(int, std::_Placeholder<2>))(int, int)> (int)>'
function(_Functor);
^
1 error generated.
Fwiw,我真正想做的是并行。我有一个功能
void MyFunction(A& a, B& b, const char** thing);
其中A 和B 是类名。我有另一个函数需要回调:
C DoStuff(const std::string& s, std::function<void(const char** thing)> f);
然后我尝试调用它
DoStuff("Hello!", std::bind(MyFunction, an_a, a_b, _3));
我收到关于没有可行转换的错误。
【问题讨论】:
-
std::bind函数返回一个未指定类型的对象。您不能依赖该类型来限制合法操作。如果您执行合法操作,您将获得理智的结果。但是编译器不能保护你不做错事。未指定的类型不是类型安全的。 -
啊哈,所以即使在编译时它也无法确定类型。好的,我会接受实现
std::bind是我不擅长的模板编程级别。但是为什么我对std::function的转换失败了?以及为什么jj_3(7)无法编译? -
@ecatmur 是的,这几乎是一个骗局。
-
不要使用 std::bind。请改用 lambda 表达式。