tr1::mem_fn и tr1::bind: на const-правильность и перегрузку

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

#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-qualifier смешивают оба 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 ответа

Решение

Поиск выполняется в то время, когда постоянство 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. При передаче указателя на функцию-член необходимо указать его подпись (если она перегружена)
  2. bind() аргументы передаются по значению.

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

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

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

Данный вызываемый объект:

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

bind() будет пересылать a к правильному operator() в соответствии с х постоянством.

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

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

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

Другие вопросы по тегам