2014-10-10 56 views
9

如果我有这个简单的例子:为什么不用std :: bind帐户来进行函数声明?

struct Foo 
{ 
    void bar(); 
    void baz(int); 
}; 

这是有道理的,这将编译:

Foo foo; 
auto f = std::bind(&Foo::bar, &foo); 

但是为什么bind以这样的方式来设计,这编译:

auto g = std::bind(&Foo::baz, &foo); 

我可以拨打f,但我永远不能拨打g。为什么要编译?什么是落后,需要我的理由不得不这样做:

auto g2 = std::bind(&Foo::baz, &foo, std::placeholders::_1); 

我能理解使用占位符,如果你想惹参数获得通过以及以什么顺序,但为什么不只是默认过关全部参数以正确的顺序而不必指定它?

+1

大概是因为没有办法得到的参数个数这意味着生成的函数对象必须允许*任意数量的参数,包括none,如果(例如)'g'被“调用”而没有参数,会导致未定义的行为。 – 2014-10-10 11:36:11

+6

我认为'std :: placeholders'执行两个函数,1.如你所说,它们将参数从源代码传递到汇编代码,2.它们表示需要多少个参数。 – Niall 2014-10-10 11:40:57

+3

boost库可能有更多与“bind”相关的原始设计原理。 – Niall 2014-10-10 11:41:51

回答

3

但为什么会结合这样的方式设计,这编译:
auto g = std::bind(&Foo::baz, &foo);
我可以叫f,但我永远不能叫g。为什么要编译?

Boost.Bind FAQ说Boost.Bind通常会在诊断“绑定时间”这样的错误(即你在哪里打电话bind行)。然而,标准并没有要求对std::bind,而不是它在以下需要std::bind元件:

INVOKE (fd, w1, w2, ..., wN)(20.9.2)应为某些值W1有效的表达式,W2, ...,wN,其中N == sizeof...(bound_args)

这意味着你的代码违反了函数的前提条件,这会导致未定义的行为。标准库的实现没有义务检查违反先决条件,这是你的工作。这个库也不禁止检查它们,所以它会符合一个实现来拒绝它,就像Boost.Bind一样。我会向图书馆供应商提出请求,要求他们在可能的情况下诊断无效的绑定表达式,作为“实施质量”增强功能。

为什么不只是默认通所有按照正确的顺序的参数,而不必指定呢?

我能想到两个原因。

首先,通过bind创建的调用包装的行为是丢弃不对应于一个占位符参数,所以你可以调用x(1, 2, 3)并让它忽略所有的参数,并调用foo.bar()。这是一种通用模式的一部分,您可以使用bind来包装一个N-arity函数,以创建一个完全不同的元素的调用包装器,该元素可能会添加参数,删除它们,修复某些特定的绑定值等。如果在绑定表达式中未使用占位符时的默认行为是转发所有参数,则不可能使所有参数都被删除。

其次,总是要求你明确哪些参数要以哪个顺序传递,这更加一致。一般来说,只有在没有绑定参数的情况下传递所有调用参数才有意义,否则bind应该如何知道是否在绑定参数之前或之后传递调用参数?

例如鉴于

struct X { 
    void f(int, int) { } 
} x; 
auto h = bind(&X::f, &x, 1); 
h(2); 

x.f(1, 2)x.f(2, 1)调用h(2)结果呢?由于当存在绑定参数时的正确行为并不明显,所以当没有占位符时,自动转发所有参数只有在没有绑定参数时才有意义(因为不存在绑定参数应该先出现还是后出现的问题) ,这是一个相当特殊的情况。改变API的一个重要特性来处理这种特殊情况将具有可疑价值,尤其是当它使得不可能实现的情况下。

另一种解决方案是继续要求用户明确他们想要的内容,但提供一个明确的方式来表达TomaszKamiński在N4171中提出的“只转发所有内容”,这将在接下来的C++委员会会议上讨论周。该_all占位解决决定调用参数是否应该来绑定参数之前或之后,因为你可以明确地说,你是否想问题bind(f, arg1, arg2, std::placeholders::_all)bind(f, std::placeholders::_all, arg1, arg2)甚至bind(f, arg1, std::placeholders::_all, arg2)

+0

那么,您如何诊断无效绑定表达式作为QoI增强功能? :) – Barry 2014-10-30 14:11:12

+1

好主意!我会研究它:) – 2014-10-30 14:30:32

+0

GCC中继现在检查绑定表达的arity,https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00032.html – 2014-11-03 03:04:00

相关问题