我有类似于在c ++中将不同的lambdas传递给函数模板的问题,但现在使用由std::bind而不是lambdas创建的包装器。
我有两个重载方法Add ,它们采用不同形式的std::function :
template<typename T> struct Value { T value; }; template <typename T> void Add(Value<T> &value, function<bool()> predicate) { } template <typename T> void Add(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate) { }这现在对lambda表达式正常工作,但与函数绑定与std::bind失败:
struct Predicates { bool Predicate0() { return true; } bool Predicate1(const Value<int> &) { return true; } }; Predicates p; Add(i, std::bind(&Predicates::Predicate0, &p));失败
错误C2668:'添加':对重载函数的模糊调用
和
Add(i, std::bind(&Predicates::Predicate1, &p, _1));使用静态断言失败(Visual C ++ 2015,Update 3):
元组索引超出范围
有没有办法使它与lambdas和绑定的函子一起工作? 我会考虑使用SFINAE来启用基于is_bindable_expression的单个重载并检查参数类型但我没有把它放在一起。
I have problem similar to Passing different lambdas to function template in c++ but now with wrappers created by std::bind instead of lambdas.
I have two overloads of method Add that take different forms of std::function:
template<typename T> struct Value { T value; }; template <typename T> void Add(Value<T> &value, function<bool()> predicate) { } template <typename T> void Add(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate) { }This now works fine with lambdas but fails with functors bound with std::bind:
struct Predicates { bool Predicate0() { return true; } bool Predicate1(const Value<int> &) { return true; } }; Predicates p; Add(i, std::bind(&Predicates::Predicate0, &p));fails with
error C2668: 'Add': ambiguous call to overloaded function
and
Add(i, std::bind(&Predicates::Predicate1, &p, _1));fails with static assert (Visual C++ 2015, Update 3):
tuple index out of bounds
Is there a way to make it work both with lambdas and bound functors? I would think of using SFINAE to enable the individual overload based on is_bindable_expression and checking the argument type but I'm failing to put it together.
最满意答案
停止使用std::bind 。 这是一个随机的功能和怪癖混乱。
今天的怪癖是, std::bind将接受无限数量的参数并丢弃任何额外的参数。 明天你可能会遇到这样一个事实:将std::bind结果传递给std::bind会产生奇怪的效果。
std::bind被移植到同一时间增加了语言的lambdas。 Lambdas几乎解决了每个问题bind问题,就像清晰的语法一样,并且没有让怪癖bind问题,特别是在auto lambda表达式可用后的C ++ 14之后。 (大多数C ++ 11编译器也支持auto lambda)。
您可以编写函数,使其中一个或另一个在他们都适用时是首选的超载。 但是这样做会给你的界面增加一堆噪音,在这种情况下,你想要这个偏好的唯一原因是因为std::bind做了一些愚蠢的事情。
围绕设计不佳的std库进行工程是不值得的。 只需停止使用std库的设计不佳的地方,或者在明确使用的地方使用。
如果没有,请这样做:
template <class T, class F, std::enable_if_t< std::is_convertible< std::result_of_t<std::decay_t<F> const&(Value<T> const&)>, bool >{}, int > = 0 > void Add(Value<T> &value, F&& f) { // do pass f Value<T> } template <class T, class F, std::enable_if_t< !std::is_convertible< std::result_of_t<std::decay_t<F> const&(Value<T> const&)>, bool >{} && std::is_convertible< std::result_of_t<std::decay_t<F> const&()>, bool >{}, int > = 0 > void Add(Value<T> &value, F&& f) { // do not pass f Value<T> }我们在这里抛出一些令人讨厌的SFINAE检测,在你想使用的两个重载中选择哪一个,并明确地选择一个。
这不值得。
Stop using std::bind. It is a mess of random features and quirks.
Todays quirk is that std::bind will accept an unlimited number of arguments and discard any extra ones. Tomorrow you might run into the fact that passing std::bind result to std::bind does strange magic.
std::bind was ported over to boost at the same time lambdas where added to the language. Lambdas solve almost every problem bind does in just as clear syntax and fails to have the myraid of quirks bind does, especially post C++14 when auto lambdas are available. (Most C++11 compilers also supported auto lambda).
You can write functions so that one or the other is the preferred overload when they both apply. But doing so adds a pile of noise to your interface, and in this case about the only reason why you'd want that preference is because std::bind is doing something stupid.
Engineering around a poorly designed bit of std library is not worth it. Simply stop using that poorly designed bit of std library, or at point of use cast explicitly.
Failing that, do this:
template <class T, class F, std::enable_if_t< std::is_convertible< std::result_of_t<std::decay_t<F> const&(Value<T> const&)>, bool >{}, int > = 0 > void Add(Value<T> &value, F&& f) { // do pass f Value<T> } template <class T, class F, std::enable_if_t< !std::is_convertible< std::result_of_t<std::decay_t<F> const&(Value<T> const&)>, bool >{} && std::is_convertible< std::result_of_t<std::decay_t<F> const&()>, bool >{}, int > = 0 > void Add(Value<T> &value, F&& f) { // do not pass f Value<T> }where we throw some nasty SFINAE detection on which of the two overloads you want to use, and explicitly prefer one.
This is not worth it.
更多推荐
发布评论