2

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?

3
  • Fwiw, just use a lambda: auto foo = [&ma](auto some_param){ return ma[some_param]; }; Commented Jan 25, 2020 at 14:06
  • You are probably aware of this, but let me point out that operator[] and at are not equivalent. at performs bounds checking and is therefore safer and less efficient. Commented Jan 25, 2020 at 14:39
  • @Tom I have written the answer so please take a look at it and give it an upvote and / or accept it (that green tick beneath the votes) if it helped you Commented Jan 26, 2020 at 8:53

1 Answer 1

3

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.