weird compiler error using bind2nd(): "member function already defined or declared" instead of "reference to reference"
Asked Answered
T

2

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.
Trengganu answered 10/9, 2012 at 10:20 Comment(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.Phenazine
looks like it refers to op()of the binder2nd struct, which due to reference folding (or similar) got defined twice with the same signature.Guitarist
This is quite interesting. It would seem that you can't have reference argument types in the old binder wrappers?!Vanesavanessa
S
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.

Sheridansherie answered 10/9, 2012 at 11:18 Comment(1)
+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. :-/Vladi
V
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>.

Vanesavanessa answered 10/9, 2012 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.