Почему этот фрагмент кода компилируется с VS2010, а не с GCC 4.5.2? - PullRequest
1 голос
/ 14 сентября 2011
#include <functional>
#include <memory>
#include <iostream>

using namespace std;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    return 0;
}

Объекты GCC для второго оператора связывания присваиваются объекту функции с подписью shared_ptr. Вот вывод ошибки.

/ usr / include / c ++ / 4.5 / function: 2103 | 6 | создается из ‘Std :: function <_Res (_ArgTypes ...)> :: function (_Functor, typename std :: enable_if <(! std :: is_integral <_Functor> :: value), std :: function <_Res (_ArgTypes ...)> :: _ Бесполезно> :: type) [with _Functor = std :: _ Bind (std :: _ Placeholder <1>)>, _Res = void, _ArgTypes = {std :: shared_ptr}, имя типа std :: enable_if <(! std :: is_integral <_Functor> :: value), std :: function <_Res (_ArgTypes ...)> :: _ Бесполезно> :: type = станд :: функция)> :: _ Бесполезные] | /home/craig/work/litd/test/main.cpp:29|97| приведено здесь | /usr/include/c++/4.5/functional|1713|error: нет совпадений для вызова «(Станд :: _ Bind (станд :: _ Заполнитель <1>)>) (Станд :: shared_ptr)»| || === Сборка завершена: 1 ошибка, 0 предупреждений === |

Edit: Больше загадки, когда я изменяю заголовки включения на их эквиваленты tr1, он компилируется.

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

using namespace std::tr1;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    return 0;
}

Ответы [ 2 ]

1 голос
/ 14 сентября 2011

Это похоже на ошибку в реализации g ++ std::function или, может быть, std::bind, в зависимости от того, можете ли вы вызвать объект, возвращенный bind(&Foo::Bar, placeholders::_1) с помощью foo;если это работает:

auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(foo);

, тогда может показаться, что реализация std::function в g ++ не завершена.В противном случае может показаться, что реализация std::bind является неполной.

[20.8.9.1.2] Шаблон функции bind состояния:

template<class F, class... BoundArgs>
  unspecified bind(F&& f, BoundArgs&&... bound_args);

...

Возвращает : Оболочка переадресации вызовов g со слабым типом результата (20.8.2).Эффект g(u1, u2, ..., uM) должен быть <em>INVOKE</em>(fd, v1, v2, ..., vN, result_of::type)

[20.8.2] Состояния требований:

Определить <em>INVOKE</em>(f, t1, t2, ..., tN) следующим образом:

- (t1.*f)(t2, ..., tN) когда f является указателем на функцию-член класса T и t1 является объектом типа T или ссылкой на объект типа T или ссылкой на объекттипа, производного от T;

- ((*t1).*f)(t2, ..., tN), когда f является указателем на функцию-член класса T, а t1 не является одним из типов, описанных в предыдущемitem;

...

При связывании &Foo::Bar возвращаемая «оболочка переадресации вызова» принимает один аргумент, u1.Назовите его тип U1.Далее в [20.8.9.1.2] говорится, что поскольку первый тип аргумента шаблона в BoundArgs был типом заполнителя _1, тип V1 равен U1&&.

Передача std::shared_ptr<Foo> для оболочки переадресации вызовов, возвращаемой bind(&Foo::Bar, placeholders::_1), следует разрешить, поскольку применяется случай 2 из [20.8.2].

EDIT: Я использую ту же версию g ++, что и вы, 4.5.2, в Windows (MinGW).Для меня следующие компиляции просто отлично:

#include <functional>
#include <memory>
#include <iostream>

using namespace std;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    //function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    auto fn2 = bind(&Foo::Bar, placeholders::_1);
    fn2(foo);
    return 0;
}

Таким образом, похоже, это реализация g ++ 1070 *, которая виновата.

EDIT2: Следующие ошибки:

auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(std::shared_ptr<Foo>(foo));

SO7408263.cpp: 19: 31: ошибка: нет совпадения для вызова '(std :: _ Bind (std :: _ Placeholder <1>)>) (std :: shared_ptr) '

Возможно, в конце концов std::bind.

0 голосов
/ 14 сентября 2011

Функция ожидает, что ->* будет перегружен для использования указателя на член. Я считаю, что shared_ptr не обеспечивает эту функциональность. Спецификация TR1 могла требовать специализации, но C ++ 11 - нет. В Visual Studio C ++ 11 shared_ptr определяется как версия TR1, что объясняет разницу.

...