странна грешка на компилатора при използване на bind2nd(): членска функция вече е дефинирана или декларирана вместо препратка към препратка

Наскоро прекарах доста време в разбиране на съобщението за грешка при извикване на func() в този код:

int main()
{
    vector< vector<double> > v;

    double sum = 0;
    for_each( v.begin(), v.end(), 
        bind2nd( ptr_fun(func), &sum ) );

    return 0;
}

когато func() беше деклариран така, кодът се компилира добре:

void func( vector<double> v, double *sum )
{
}

когато използвах тази декларация (за ефективност), получих грешка на компилатора:

void func( const vector<double> &v, double *sum )
{
}

Грешката, която очаквах да видя, беше нещо като грешка препратка към препратка, поради дефиницията на operator() на binder2nd,

result_type operator()(const argument_type& _Left) const

Вместо това, за моя изненада, грешката, която ми даде компилаторът на Visual C++ (VS2012), беше:

грешка C2535: 'void std::binder2nd‹_Fn2>::operator ()(const std::vector‹_Ty> &) const': функция член вече е дефинирана или декларирана

които не мога да дешифрирам.

  • Можете ли да обясните при какъв механизъм operator() е вече дефиниран?

Пълната грешка, която получих, беше:

error C2535: 'void std::binder2nd<_Fn2>::operator ()(const std::vector<_Ty> &) const' : member function already defined or declared
with
[
     _Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>,
      _Ty=double
]
c:\vc\include\xfunctional(319) : see declaration of 'std::binder2nd<_Fn2>::operator ()' 
with
[
      _Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
] 
c:\consoleapplication1.cpp(31) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled 
with 
[
       _Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]

Build FAILED.

person Grim Fandango    schedule 10.09.2012    source източник
comment
Тъй като използвате VS 2012, мисля, че можете просто да преминете към C++11 и да използвате lambdas/std::bind, за да избегнете тези остарели неща.   -  person kennytm    schedule 10.09.2012
comment
изглежда, че се отнася до op() на структурата binder2nd, която поради сгъване на референт (или подобно) е дефинирана два пъти с един и същ подпис.   -  person PlasmaHH    schedule 10.09.2012
comment
Това е доста интересно. Изглежда, че не можете да имате референтни типове аргументи в старите опаковки на binder?!   -  person Kerrek SB    schedule 10.09.2012


Отговори (2)


Това поведение е добре дефинирано (всеки правилен C++ компилатор няма да успее да компилира вашия код).

От стандартния (N3376) раздел D.9.3 на шаблон на клас binder2nd съществуват тези две дефиниции на operator():

typename Fn::result_type
operator()(const typename Fn::first_argument_type& x) const;

typename Fn::result_type
operator()(typename Fn::first_argument_type& x) const;

Ако first_argument_type вече е const T&, тогава те ще бъдат в конфликт.

person Travis Gockel    schedule 10.09.2012
comment
+1, изглежда, че това дори е проблем, ако first_argument_type вече е T&? Поне открих, че std::bind2nd(std::ptr_fun(f), "xyz"); не успява да се компилира с абсолютно същата грешка, ако f е void f(std::ostream &str, const char *s);. Уви, предаването на std::ostream по стойност не е опция, така че изглежда трябва да прибегнете до предаване на указател към него. :-/ - person Frerich Raabe; 03.07.2014

Това не е отговор, но просто искам да запиша модерното решение C++11, където всички малки помощници за свързване са отхвърлени в полза на универсалния std::bind:

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

void func(std::vector<double> const & v, double * sum) { /* ... */ }

int main()
{
    std::vector<std::vector<double>> v;
    double sum = 0;
    std::for_each(v.begin(), v.end(), std::bind(func, std::placeholders::_1, &sum));
}

Вариативните шаблони на C++11, както и по-изчерпателна колекция от черти, модифициращи типа, дават на std::bind много по-силни способности за дедукция от предишните компоненти в <functional>.

person Kerrek SB    schedule 10.09.2012