8

I recently spent quite some time understanding the error message when calling func() in this piece of code:

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

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

    return 0;
}

when func() was declared like so, the code compiled fine:

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

when I used this declaration (for efficiency), I got a compiler error:

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

The error I expected to see was something like a reference-to-reference error, because of the definition of operator() of binder2nd,

result_type operator()(const argument_type& _Left) const

Instead, to my surprise, the error the Visual C++ (VS2012) compiler gave me was:

error C2535: 'void std::binder2nd<_Fn2>::operator ()(const std::vector<_Ty> &) const' : member function already defined or declared

which I cannot decipher.

  • Can you explain under which mechanism the operator() is already defined?

The full error I got was:

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.
Grim Fandango
  • 2,296
  • 1
  • 19
  • 27
  • 3
    Since you're using VS 2012, I think you could just switch to C++11 and use lambdas/`std::bind` to avoid these deprecated stuff. – kennytm Sep 10 '12 at 10:29
  • 1
    looks like it refers to op()of the binder2nd struct, which due to reference folding (or similar) got defined twice with the same signature. – PlasmaHH Sep 10 '12 at 10:33
  • This is quite interesting. It would seem that you can't have reference argument types in the old binder wrappers?! – Kerrek SB Sep 10 '12 at 10:52

2 Answers2

6

This behavior is well-defined (every correct C++ compiler will fail to compile your code).

From the standard (N3376) section D.9.3 on class template binder2nd, these two defintions of operator() exist:

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;

If first_argument_type is already a const T&, then they will be conflicting.

Travis Gockel
  • 26,877
  • 14
  • 89
  • 116
  • +1, it appears that this is even an issue if `first_argument_type` is already a `T&`? At least I found that `std::bind2nd(std::ptr_fun(f), "xyz");` fails to compile with the exact same error if `f` is `void f(std::ostream &str, const char *s);`. Alas, passing `std::ostream` by value is not an option, so it seems you have to resort passing a pointer to it. :-/ – Frerich Raabe Jul 03 '14 at 09:21
1

This isn't an answer, but I just want to record the modern C++11 solution, where all the small bind helpers are deprecated in favour of the universal 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));
}

The variadic templates of C++11, as well as a more comprehensive collection of type-modifying traits, give std::bind much stronger deduction abilities than the previous components in <functional>.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084