Как избежать явного приведения с помощью временных объектов std::bind()?

Тип возвращаемого значения std::bind (намеренно) не указан. Его можно хранить в std::function.

В приведенном ниже примере программы показано, как мне нужно явно преобразовать временный объект, возвращаемый std::bind(), в std::function, чтобы вызвать fn1().

Если бы возвращаемый тип std::bind был известен, я мог бы перегрузить конструктор обратного вызова, и мне больше не нужно было бы явно приводить временные объекты std::bind.

Есть ли способ избежать явного приведения?

// g++ -std=c++11 test.cxx
#include <functional>

using std::placeholders::_1;

class A
{
    public:
        void funcA (int x) { }
};

class Callback
{
    public:
        Callback () = default;
        Callback (std::function<void(int)> f) { }
        // Wish we knew the return type of std::bind()
        // Callback (return_type_of_std_bind f) { }
};

void fn0 (std::function<void(int)> f) { }
void fn1 (Callback cb) { }

int main (void)
{
    A a;
    fn0(std::bind(&A::funcA, &a, _1)); // ok
    fn1(std::function<void(int)>(std::bind(&A::funcA, &a, _1))); // ok, but verbose
    fn1(std::bind(&A::funcA, &a, _1)); // concise, but won't compile
}

Вероятно, это не имеет значения, но я использую gcc 4.7.2 в Linux.


person Scott Smedley    schedule 15.01.2013    source источник
comment
Какую ошибку компиляции вы получаете?   -  person Nicol Bolas    schedule 16.01.2013
comment
Вместо того, чтобы пытаться узнать то, что (по замыслу) не должно быть известно, не задавайте вопрос. Не пытайтесь узнать тип, напишите конструктор, которому не нужно знать тип... в этот момент вы должны думать о шаблоне.   -  person Jonathan Wakely    schedule 16.01.2013


Ответы (1)


Лучше всего дать Callback универсальный конструктор:

struct Callback
{
    typedef std::function<void(int)> ftype;
    ftype fn_;

    template <typename T,
              typename = typename std::enable_if<std::is_constructible<ftype, T>::value>::type>
    Callback(T && f) : fn_(std::forward<T>(f))
    { }
};

(Я добавил второй аргумент шаблона по умолчанию, чтобы включить этот конструктор только для типов T, для которых оператор имеет смысл, чтобы не создавать ложные свойства конвертируемости.) Обратите внимание, как этот метод удаляет одно неявное определяемое пользователем преобразование из цепочки преобразований, вызвав явный конструктор для fn_.

person Kerrek SB    schedule 15.01.2013
comment
И, чтобы констатировать очевидное, если он не хочет, чтобы это было переменной-членом, вы также можете просто иметь локальную переменную. - person Seth Carnegie; 16.01.2013