c++c++11constantsbindfunction-reference

std::bind on operator[] of std::array


I am trying to bind a member function at or operator[] of std::array, but the compiler (gcc 7.3) says that it can't determine the typename _Func. So I had created my own struct array to see where the problem is. But it works fin in this case.

#include <iostream>
#include <functional>
#include <array>

template<typename ret, unsigned int size>
struct my_arr {
    ret data[size];

    ret& at(unsigned int i) {return data[i];}

    ret& operator[](unsigned int i){return data[i];}
};

using namespace std::placeholders;
using namespace std;

int main() {

    my_arr<int,3> ma = {1,2,3};

    auto x = std::bind(&my_arr<int,3>::at, _1, 0); // ok

    auto x1 = std::bind(&my_arr<int,3>::operator[], _1, 0); // ok

    auto arr_x = std::bind(&array<double, 3>::at, _1, _2); // error

    auto arr_x = std::bind(&array<double, 3>::operator[], _1, _2); // error

    std::cout << x(ma) << std::endl << x1(ma) << std::endl;

}

The compile error is:

no matching function for call to 'bind(, const std::_Placeholder<1>&, const std::_Placeholder<2>&)' auto arr_x = std::bind(&array::at, _1, _2); ^


I have realized what causes this error, but I still don't know how to solve it. The problem is that the compiler doesn't know which function do I reffer to, because there are const and non-const variants of these functions. This code simulates the same error.

#include <iostream>
#include <functional>
#include <array>

template<typename ret, unsigned int size>
struct my_arr {
    ret data[size];

    ret& at(unsigned int i) {return data[i];}
    const ret& at(unsigned int i) const {return data[i];}
    ret& operator[](unsigned int i){return data[i];}
};

using namespace std::placeholders;
using namespace std;

int main() {

    my_arr<int,3> ma = {1,2,3};

    auto x = std::bind(&my_arr<int,3>::at, _1, 0); // error

    auto x1 = std::bind(&my_arr<int,3>::operator[], _1, 0); // ok

    std::cout << x(ma) << std::endl << x1(ma) << std::endl;

}

I still don't know how to specify which version of function I want to call, how to bind the const version and the non-const one?


Solution

  • Since you have two overloads:

    compiler doesn't know which function overload you really want to bind to. Therefore, you need to cast function pointer to the exact function signature.

    This would work:

    auto x = std::bind(static_cast<int&(my_arr<int, 3>::*)(unsigned int)>(&my_arr<int,3>::at), _1, 0);
    

    Check it out live

    You can also solve your problem in a more elegant way by using lambdas:

    auto x2 = [&ma](auto const p) { return ma.at(p); };
    std::cout << x2(0) << std::endl; // output: 1