Search code examples
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:

    • ret& at(unsigned int i) and
    • const ret& at(unsigned int i) const

    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