【问题标题】:tr1::mem_fn and tr1::bind: on const-correctness and overloadingtr1::mem_fn 和 tr1::bind:关于 const 正确性和重载
【发布时间】:2010-09-23 13:05:06
【问题描述】:

下面的sn-p有什么问题?

#include <tr1/functional>
#include <functional>
#include <iostream>

using namespace std::tr1::placeholders;

struct abc
{
    typedef void result_type;

    void hello(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void hello(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

int
main(int argc, char *argv[])
{
    const abc x;
    int a = 1;

    std::tr1::bind(&abc::hello, x , _1)(a);
    return 0;
}

尝试用g++-4.3编译它,似乎cv-限定符重载函数混淆了tr1::mem_fn&lt;&gt;tr1::bind&lt;&gt;,并出现以下错误:

no matching function for call to ‘bind(<unresolved overloaded function type>,...

相反,以下 sn-p 编译但似乎破坏了 const-correctness

struct abc
{
    typedef void result_type;

    void operator()(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void operator()(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

...

    const abc x;
    int a = 1;
    std::tr1::bind( x , _1)(a);

有什么线索吗?

【问题讨论】:

    标签: c++ c++11 functional-programming tr1


    【解决方案1】:

    查找是在 this 的常量未知时完成的。你只需要通过铸造给它一个提示。试试这个:

    typedef void (abc::*fptr)(int) const; // or remove const
    std::tr1::bind((fptr)&abc::hello, x , _1)(a);
    

    您可能还会注意到这里删除const 仍然有效。这是因为您应该通过指针传递 x(因为 C++ 成员函数的第一个参数,隐式 this 参数始终是指针)。试试这个:

    typedef void (abc::*fptr)(int) const; // won't compile without const (good!)
    std::tr1::bind((fptr)&abc::hello, &x , _1)(a);
    

    正如在下面我的 cmets 中发现的那样,如果您像原来一样省略 &amp;,您将传递 x 按值,这通常不是您想要的(尽管它使在您的特定示例中几乎没有实际差异)。对于bind,这实际上似乎是一个不幸的陷阱。

    【讨论】:

    • 不应期望 bind 评估作为第一个参数传递的对象的常量性,在这种情况下是 x ?那么第二个 sn-p 呢?
    • 我不知道。 bind 在您通过值(引用?)传递并且实际方法采用指针时使调用成功,但由于某种原因它没有正确处理 constness。我不知道这是为什么。如果有人拿枪指着我的脑袋让我猜,我会提到“转发问题”。
    • 啊哈!当您绑定并且不通过指针传递时,它正在制作副本。我会更新我的答案。
    • std::tr1::bind(std::tr1::ref(x) , _1)(a);也解决了线索:-)
    • 因为这个 open-std.org/Jtc1/sc22/wg21/docs/cwg_active.html#547 ,你不能做 tr1::bind(tr1::mem_fn(&abc::hello), _1);然而 -.- 让我们希望它进入 c++1x
    【解决方案2】:

    正如 John 所建议的,这些 sn-ps 中出现的问题如下:

    1. 传递成员函数指针时,必须指定其签名(如果重载)
    2. bind() 按值传递参数。

    第一个问题通过将提供的成员函数指针转换为bind来解决:

        std::tr1::bind(static_cast< void(abc::*)(int) const >(&abc::hello), x, _1)(a);
    

    第二个可以通过按地址传递可调用对象(如约翰建议)或通过 TR1 reference_wrapper&lt;&gt; 来解决——否则它将按值传递,使 const-correctness 打破幻觉。

    给定 x 一个可调用对象:

    std::tr1::bind( std::tr1::ref(x) , _1)(a);
    

    bind() 将根据 x constnessa 转发到正确的operator()

    【讨论】:

      【解决方案3】:

      这个问题已经回答了,但我发现用 bind 指定重载的最好方法是在模板上指定它:

      std::tr1::bind<void(foo::*)(int)>(&foo::bar);
      

      此方法同样显式,但比强制转换短(无论如何使用 static_cast。但它比 C-cast 更干净,长度相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-07
        • 1970-01-01
        • 1970-01-01
        • 2011-08-08
        相关资源
        最近更新 更多