tr1 :: mem_fn и tr1 :: bind: на const-правильность и перегрузку - PullRequest
4 голосов
/ 22 ноября 2008

Что не так со следующим фрагментом?

#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<> и tr1::bind<> и выдает следующую ошибку:

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

Вместо этого следующий фрагмент компилируется, но, кажется, нарушает const-правильность :

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);

Любая подсказка?

Ответы [ 3 ]

3 голосов
/ 22 ноября 2008

Поиск выполняется в то время, когда константа 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);

Как было обнаружено в моих комментариях ниже, если вы пропустите &, как вы это делали изначально, вы передадите x по значению , что обычно не то, что вы хотите (хотя это мало что дает практическая разница в вашем конкретном примере). Это на самом деле похоже на неудачную ловушку для bind.

1 голос
/ 30 ноября 2008

На этот вопрос ответили, но я считаю, что лучший способ указать перегрузку с помощью bind - это указать ее в шаблоне:

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

Этот метод такой же явный, но короче, чем приведение (в любом случае static_cast. Но он чище, чем C-cast, такой же длины.

0 голосов
/ 22 ноября 2008

Как предположил Джон, проблемы, возникающие в этих фрагментах, следующие:

  1. При передаче указателя на функцию-член необходимо указать его подпись (если перегружена)
  2. bind() передаются аргументы по значению.

Первая проблема решается путем приведения указателя на функцию-член, предоставленного для связывания:

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

Второе может быть решено путем передачи вызываемого объекта по адресу (как предложил Джон) или с помощью TR1 reference_wrapper<> - в противном случае он будет передан по значению, в результате чего const -корректность нарушит галлюцинацию .

Учитывая х вызываемый объект:

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

bind() перешлет a на правильный operator() в соответствии с x constness .

...