Re[3]: bind2nd
От: Павел Кузнецов  
Дата: 28.03.02 14:59
Оценка: 4 (1)
Здравствуйте Bell, Вы писали:

ПК>>После исправлений, указанных выше, под STLport будет работать.

B>А вот и нет
B>Дело не в этом (причину я указал в предыдущем ответе)

Тут вы, батенька, поторопились Вашу mem_fun1_ref_t_corrected следовало назвать mem_fun1_ref_t_broken, т.к. теперь через нее нельзя вызывать неконстантные члены-функции. По стандарту (см. 20.3.8) шаблон mem_fun1_ref_t объявлен так:
template <class S, class T, class A> class mem_fun1_ref_t
    : public binary_function<T, A, S> {
public:
    explicit mem_fun1_ref_t(S (T::*p)(A));
    S operator()(T& p, A x) const;
};


Кроме того, для константных функций-членов есть еще const_mem_fun1_ref_t:

template <class S, class T, class A> class const_mem_fun1_ref_t
    : public binary_function<T, A, S> {
public:
    explicit const_mem_fun1_ref_t(S (T::*p)(A) const);
    S operator()(const T& p, A x) const;
};


Второй шаблон отсутствует в MSVC++6.0.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
bind2nd
От: WeCom Беларусь  
Дата: 28.03.02 09:22
Оценка:
Как в VC 6.0 заставить откомпилиться следующий код?
#include <vector>
#include <functional>
#include <algorithm>

using namespace std;

class A
{
public:
    int Func1(int i){ return 0; }
};

int main(int argc, char* argv[])
{
    vector<A> v;
    for_each(v.begin(),v.end(),bind2nd(mem_fun1_ref( A::Func1 ),10) );
    return 0;
}

Под родным stl одна ошибка, под stlport другая. Интересуют соображения по обоих случаях
Re: bind2nd
От: Павел Кузнецов  
Дата: 28.03.02 14:13
Оценка:
WC>class A
WC>{
WC>public:
WC>    int Func1(int i){ return 0; }


int Func1(int i) const...

WC>    for_each(v.begin(),v.end(),bind2nd(mem_fun1_ref( A::Func1 ),10)


Должно быть &A::Func1, хотя MSVC++6.0 этого и не требует.

WC>Под родным stl одна ошибка, под stlport другая. Интересуют соображения по обоих случаях


После исправлений, указанных выше, под STLport будет работать. С родной STL дело чуть хуже. В заголовке <functional> не хватает версий std::mem_fun... для константных функций-членов.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: bind2nd
От: Bell Россия  
Дата: 28.03.02 14:37
Оценка:
Здравствуйте WeCom, Вы писали:

WC>Как в VC 6.0 заставить откомпилиться следующий код?

WC>
WC>#include <vector>
WC>#include <functional>
WC>#include <algorithm>

WC>using namespace std;

WC>class A
WC>{
WC>public:
WC>    int Func1(int i){ return 0; }
WC>};

WC>int main(int argc, char* argv[])
WC>{
WC>    vector<A> v;
WC>    for_each(v.begin(),v.end(),bind2nd(mem_fun1_ref( A::Func1 ),10) );
WC>    return 0;
WC>}
WC>

WC>Под родным stl одна ошибка, под stlport другая. Интересуют соображения по обоих случаях

В стандартном варианте класс mem_fun_ref_t объявлен так:

template<class _R, class _Ty, class _A>
class mem_fun1_ref_t : public binary_function<_Ty * , _A, _R>


при этом получается, что mem_fun1_ref_t::first_argument_type есть A*!!! (A — имя твоего класса), а bind2nd<Pred> использует Pred::first_argument_type в operator(), и в твоем случае этот тип должен соответствовать A, что при имеющемся объявлении mem_fun1_ref_t не так.

Я немного подправил mem_fun1_ref, и вот что получилось в результате (нужные места выделены жирным шрифтом):

template<class _R, class _Ty, class _A>
    class mem_fun1_ref_t_corrected : public binary_function<_Ty , _A, _R> {
public:
    explicit mem_fun1_ref_t_corrected(_R (_Ty::*_Pm)(_A))
        : _Ptr(_Pm) {}
    _R operator()(const _Ty& _X, _A _Arg) const
        {return ((_X.*_Ptr)(_Arg)); }
private:
    _R (_Ty::*_Ptr)(_A);
    };

template<class _R, class _Ty, class _A> inline
    mem_fun1_ref_t_corrected<_R, _Ty, _A> mem_fun1_ref_corrected(_R (_Ty::*_Pm)(_A))
    {return (mem_fun1_ref_t_corrected<_R, _Ty, _A>(_Pm)); }


теперь, если использовать mem_fun1_ref_corrected, все работает как надо...

Но в душу закрадываются сомнения — зачем было объявлять mem_fun1_ref_t именно так?!
В каких-то других местах предполагается, что first_argument_type должен быть указателем?
Хотя в STLPort все объявлено нормально, т.е.

template <class _Ret, class _Tp, class _Arg>
class mem_fun1_ref_t : public binary_function<_Tp,_Arg,_Ret>


но остается другая проблема — параметр __r в

_Ret operator()(_Tp& __r, _Arg __x) const { return (__r.*_M_f)(__x); }

объявлен без модификатора
const
, что тоже неверно, т.к. при вызове из binder2nd
mem_fun1_ref_t::operator()
используется константный объект...

Неужели это косяк?!
Любите книгу — источник знаний (с) М.Горький
Re[2]: bind2nd
От: Bell Россия  
Дата: 28.03.02 14:50
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

ПК>Должно быть &A::Func1, хотя MSVC++6.0 этого и не требует.


ПК>После исправлений, указанных выше, под STLport будет работать.

А вот и нет
Дело не в этом (причину я указал в предыдущем ответе)
Любите книгу — источник знаний (с) М.Горький
Re[4]: bind2nd
От: Bell Россия  
Дата: 28.03.02 15:59
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:


ПК>Тут вы, батенька, поторопились :)

Эээ...
Есть маленько :shuffle:

Но все равно проблема стандартного STL не в отсутствии дополнительного "константного" шаблона, а в определении mem_fun1_ref_t:

template<class _R, class _Ty, class _A>
class mem_fun1_ref_t : public binary_function<_Ty * , _A, _R>



Тогда при использовании bind2nd, в

template<_Operation>
...
binder2nd::operator()(const typename _Operation::first_argument_type& __x) const


выражению _Operation::first_argument_type соответствует _Ty * , а for_each в качестве параметра передает объект типа _Ty
Вот это и есть причина ошибки.

Что касается приведенных Вами определений mem_fun1_ref и const_mem_fun1_ref — то здесь все нормально, но строка
for_each(v.begin(),v.end(),bind2nd(mem_fun1_ref( A::Func1 ),10) );

все равно не будет компилиться, если A::Func1 не объявлена с модификатором const.
Или есть биндер, у которого operator() объявлен так:
template<_Operation>
...
binder2nd::operator()(typename _Operation::first_argument_type& __x) const


???
Я пока ничего похожего не нашел...
Любите книгу — источник знаний (с) М.Горький
Re[5]: bind2nd
От: Павел Кузнецов  
Дата: 28.03.02 16:28
Оценка:
B>Но все равно проблема стандартного STL
Не стандартного, а старого Dinkumware

B> не в отсутствии дополнительного "константного" шаблона, а в определении mem_fun1_ref_t:

B>template<class _R, class _Ty, class _A>
B>class mem_fun1_ref_t : public binary_function<_Ty * , _A, _R>

И в этом тоже.

B>Что касается приведенных Вами определений mem_fun1_ref и const_mem_fun1_ref — то здесь все нормально, но строка

B>for_each(v.begin(),v.end(),bind2nd(mem_fun1_ref( A::Func1 ),10) );
B>все равно не будет компилиться, если A::Func1 не объявлена с модификатором const.

Более того, так как в MSVC++6.0 отсутствуют версии адаптеров для константных функций-членов, при вызове функции mem_fun1_ref(&A::Func1) компилятор выдаст ошибку о том, что не может преобразовать 'int(A::*)(int) const' к типу 'int(A::*)(int)'. На это я и указал в своем первом сообщении (может, чуть более кратко, нежели следовало)

B>Или есть биндер, у которого operator() объявлен так:

B>binder2nd::operator()(typename _Operation::first_argument_type& __x) const

Может и есть, но он не входит в стандартную библиотеку C++ и, в любом случае, в нем нет никакой необходимости, т.к. при конкретизации binder2nd<const_mem_fun1_ref_t<R, T, A> >, _Operation::first_argument_type == const T.

Резюме: для того, чтобы приведенный фрагмент кода компилировался MSVC++6.0 на "родной" STL, надо внести (как минимум) два изменения в заголовок <functional>:
  1. исправить объявление (как верно заметил Bell)
    class mem_fun1_ref_t : public binary_function<_Ty * , _A, _R> на
    class mem_fun1_ref_t : public binary_function<_Ty, _A, _R>

  2. добавить реализацию адаптеров для константных функций-членов перед строкой _STD_END
            // TEMPLATE CLASS const_mem_fun_t
    template<class _R, class _Ty>
        class const_mem_fun_t : public unary_function<const _Ty *, _R> {
    public:
        explicit const_mem_fun_t(_R (_Ty::*_Pm)() const)
            : _Ptr(_Pm) {}
        _R operator()(const _Ty *_P) const
            {return ((_P->*_Ptr)()); }
    private:
        _R (_Ty::*_Ptr)() const;
        };
            // TEMPLATE FUNCTION mem_fun
    template<class _R, class _Ty> inline
        const_mem_fun_t<_R, _Ty> mem_fun(_R (_Ty::*_Pm)() const)
        {return (const_mem_fun_t<_R, _Ty>(_Pm)); }
            // TEMPLATE CLASS const_mem_fun1_t
    template<class _R, class _Ty, class _A>
        class const_mem_fun1_t : public binary_function<const _Ty *, _A, _R> {
    public:
        explicit const_mem_fun1_t(_R (_Ty::*_Pm)(_A) const)
            : _Ptr(_Pm) {}
        _R operator()(const _Ty *_P, _A _Arg) const
            {return ((_P->*_Ptr)(_Arg)); }
    private:
        _R (_Ty::*_Ptr)(_A) const;
        };
            // TEMPLATE FUNCTION mem_fun1
    template<class _R, class _Ty, class _A> inline
        const_mem_fun1_t<_R, _Ty, _A> mem_fun1(_R (_Ty::*_Pm)(_A) const)
        {return (const_mem_fun1_t<_R, _Ty, _A>(_Pm)); }
            // TEMPLATE CLASS const_mem_fun_ref_t
    template<class _R, class _Ty>
        class const_mem_fun_ref_t : public unary_function<const _Ty, _R> {
    public:
        explicit const_mem_fun_ref_t(_R (_Ty::*_Pm)() const)
            : _Ptr(_Pm) {}
        _R operator()(const _Ty& _X) const
            {return ((_X.*_Ptr)()); }
    private:
        _R (_Ty::*_Ptr)() const;
        };
            // TEMPLATE FUNCTION mem_fun_ref
    template<class _R, class _Ty> inline
        const_mem_fun_ref_t<_R, _Ty> mem_fun_ref(_R (_Ty::*_Pm)() const)
        {return (const_mem_fun_ref_t<_R, _Ty>(_Pm)); }
            // TEMPLATE CLASS const_mem_fun1_ref_t
    template<class _R, class _Ty, class _A>
        class const_mem_fun1_ref_t : public binary_function<const _Ty, _A, _R> {
    public:
        explicit const_mem_fun1_ref_t(_R (_Ty::*_Pm)(_A) const)
            : _Ptr(_Pm) {}
        _R operator()(const _Ty& _X, _A _Arg) const
            {return ((_X.*_Ptr)(_Arg)); }
    private:
        _R (_Ty::*_Ptr)(_A) const;
        };
            // TEMPLATE FUNCTION mem_fun1_ref
    template<class _R, class _Ty, class _A> inline
        const_mem_fun1_ref_t<_R, _Ty, _A> mem_fun1_ref(_R (_Ty::*_Pm)(_A) const)
        {return (const_mem_fun1_ref_t<_R, _Ty, _A>(_Pm)); }
что подтверждается полевыми испытаниями
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.